我有一个结构的命名空间,代表各种度量单位(米,英尺,英寸等)......总共12个,由T4模板生成:)。
每个struct都带有隐式转换运算符,以支持将值转换为任何其他度量值类型,因此以下sytax是合法的:
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框架标准,所有字符串格式化和解析都由外部FormatProvider处理,后者实现ICustomFormatter。遗憾的是,这意味着该值在传递给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:我已经检查了this post,虽然问题类似,但这不是我想要的。
答案 0 :(得分:3)
嗯,这是将拆箱转换与用户定义转换分开的问题。您希望两者都发生 - 您必须指定要取消选择的类型,以及让编译器知道何时需要用户定义的转换。除非您使用动态类型,否则必须在 compile 时选择用户定义的转换,因此编译器需要知道它尝试转换的类型。
一个选项是拥有所有结构实现的IDistance
接口。然后你可以使用:
IDistance distanceArg = arg as IDistance;
if (distanceArg != null)
{
Distance distance = distanceArg.ToDistance();
}
由于你已经有了盒装价值,使用界面不会导致额外的拳击或类似的东西。每个ToDistance
实现可能只使用隐式转换:
public Distance ToDistance()
{
return this;
}
...或者您可以使用ToDistance
进行转化。
答案 1 :(得分:1)
是的,这只是你必须忍受的一件事。
如果将整数推送到对象中,则会遇到同样的问题:
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