Как напрямую напечатать разбросанную структуру в C#?

StackOverflow https://stackoverflow.com/questions/3987911

  •  10-10-2019
  •  | 
  •  

Вопрос

У меня есть пространство имен структур, которые представляют различные единицы измерения (метры, ноги, дюймы и т. Д.) ... в общей сложности 12, сгенерированные любезность шаблонов T4 :).

Каждая структура несет неявные операторы литья для поддержки лишения значения любому другому типу значения измерения, поэтому следующий Sytax является законным:

var oneThousandMeters = new Meters(1000);    
Kilometers aKilo = oneThousandMeters ;     // implicit cast OK. Value = 1 Km

Чтобы добавить к радости, есть все уловки класса под названием Расстояние который может содержать любую единицу измерения, а также может быть неявно поднять на и измерение ...

var magnum = new Distance(12, DistanceUnits.Inches); 
Feet wifesDelight = magnum;               // implicit cast OK. Value = 1 foot.

Следуя стандарту .NET Framework, все форматирование и анализ строк обрабатываются внешним форматом, который реализует IcustomFormatter. К сожалению, это означает, что значение штуковывается, когда оно передается методу формата, и метод формата должен проверить объект на каждом известном типе измерения, прежде чем он сможет действовать на него. Внутренне метод формата в любом случае просто отражает измерение до значения расстояния, так что вот вопрос ....

Вопрос:

public string Format(string format, object arg, IFormatProvider formatProvider)
{
    Distance distance;           

    // The following line is desired, but fails if arg != typeof(Distance)   
    distance = (Distance)arg;    

    // But the following tedious code works:
    if(arg is Distance)
       distance = (Distance)arg;
    else if(arg is Meters)
       distance = (Distance)(Meters)arg;     // OK. compile uses implicit cast. 
    else if(arg is Feet)
       distance = (Distance)(Feet)arg;       // OK. compile uses implicit cast. 
    else if(arg is Inches)
       distance = (Distance)(Inches)arg;     // OK. compile uses implicit cast. 
    else
        ... // tear you hair out for all 12 measurement types
}

Есть ли какие -либо решения для этого, или это только один из тех неразрешимых недостатков типов стоимости?

PS: я проверил эта почта, и хотя вопрос похож, это не то, что я ищу.

Это было полезно?

Решение

Что ж, это вопрос отделения переоборудования распаковки от определенного пользователя преобразования. Вы хотите, чтобы оба произошли - и вы должны указать тип в Unbox, а также сообщить компилятору, когда вы хотите определить пользователь преобразование. Пользовательский преобразование должно быть выбрано в компиляция Время, если вы не используете динамическое печатание, поэтому компилятор должен знать, из какого типа он пытается преобразовать.

Один вариант - иметь IDistance интерфейс которые все внедряют структуры. Тогда вы могли бы просто использовать:

IDistance distanceArg = arg as IDistance;
if (distanceArg != null)
{
    Distance distance = distanceArg.ToDistance();
}

Поскольку у вас уже есть значение в штучной упаковке, использование интерфейса не вызовет дополнительное бокс или что -то в этом роде. Каждый ToDistance Реализация, вероятно, может просто использовать неявное преобразование:

public Distance ToDistance()
{
    return this;
}

... или вы можете использовать конверсию ToDistance.

Другие советы

Да, это только одна из тех вещей, с которой вы должны жить.

Вы сталкиваетесь с одним и тем же, если вы вкладываете целое число в объект:

int a = 0;
object b = a;
int c = (int)b; // this works
short d = (short)b; // this fails
short e = (short)(int)b; // this works
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top