我有一个结构的名称空间,这些名称空间代表各种度量单位(仪表,脚,英寸等)...总共12个,由T4模板产生,由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框架标准,所有字符串格式和解析均由外部A FormatProvider处理,该格式化的形式实现了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:我已经检查了 这个帖子, ,尽管问题是相似的,但这并不是我想要的。

有帮助吗?

解决方案

好吧,这是将拆箱转换与用户定义的转换分开的问题。您希望两者都会发生 - 并且必须指定输入的类型,并让编译器知道何时需要用户定义的转换。用户定义的转换必须在 编译 除非您使用动态键入,否则编译器需要知道它要转换的类型。

一种选择是有一个 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