4

我有一个结构命名空间,代表各种度量单位(米、英尺、英寸等)......总共有 12 个,由 T4 模板生成:)。

每个结构都带有隐式转换运算符以支持将值转换为任何其他测量值类型,因此以下语法是合法的:

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

更有趣的是,有一个名为Distance的包罗万象的类,它可以保存任何测量单位,也可以隐式转换为和测量值......

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

遵循 .NET 框架标准,所有字符串格式化和解析都由实现 ICustomFormatter 的外部 FormatProvider 处理。遗憾的是,这意味着值在传递给 Format 方法时会被装箱,并且 format 方法需要针对每个已知的测量类型测试对象,然后才能对其进行操作。在内部,Format 方法只是将测量值转换为距离值,所以问题来了......

问题:

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:我检查了这篇文章,虽然问题很相似,但这不是我要找的。

4

2 回答 2

5

好吧,这是将拆箱转换与用户定义的转换分开的问题。您希望两者都发生 - 您必须指定要拆箱的类型,并让编译器知道您何时需要用户定义的转换。除非您使用动态类型,否则必须在编译时选择用户定义的转换,因此编译器需要知道它试图从哪种类型进行转换。

一种选择是拥有一个所有结构都实现的IDistance 接口。然后你可以使用:

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

由于您已经获得了装箱值,因此使用接口不会导致额外的装箱或类似的事情。每个ToDistance实现可能只使用隐式转换:

public Distance ToDistance()
{
    return this;
}

...或者您可以进行转换使用ToDistance.

于 2010-10-21T13:36:12.160 回答
2

是的,这只是你必须忍受的事情之一。

如果你将一个整数塞进一个对象,你会遇到同样的事情:

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
于 2010-10-21T13:34:48.997 回答