如何在 C# 中直接键入强制转换装箱结构?
我有一个结构体的命名空间,它代表各种测量单位(米、英尺、英寸等)...总共 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 框架标准,所有字符串格式化和解析均由外部 FormatProvider 处理,该 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:我已经检查了这篇文章,尽管问题是类似,这不是我要找的。
I have a namespace of structs which represent various units of measure (Meters, Feet, Inches, etc.) ... anout 12 in total, generated courtesy of T4 templates :) .
Each struct carries implicit casting operators to support casting the value to any other measurement value-type, so the following sytax is legal:
var oneThousandMeters = new Meters(1000);
Kilometers aKilo = oneThousandMeters ; // implicit cast OK. Value = 1 Km
To add to the joy, there's a catch-all class called Distance which can hold any unit of measure, and can also be implicitly cast to and from and measurement value...
var magnum = new Distance(12, DistanceUnits.Inches);
Feet wifesDelight = magnum; // implicit cast OK. Value = 1 foot.
Following the .NET framework standard, all string formatting and parsing is handled by external a FormatProvider, which implements ICustomFormatter. Sadly, this means that the value is boxed when it is passed to the Format method, and the format method needs to test the object against every known measurement type before it can act upon it. Internally, the Format method just casts the measurement to a Distance value anyway, so here comes the question....
Question:
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
}
Are there any solutions for this, or is this just one of those unsolvable drawbacks of value types?
PS: I've checked this post, and though the question is similar, it's not what I'm looking for.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
嗯,这是将拆箱转换与用户定义转换分开的问题。您希望两者都发生 - 并且您必须指定要拆箱的类型,并让编译器知道您何时需要用户定义的转换。除非您使用动态类型,否则必须在编译时选择用户定义的转换,因此编译器需要知道它尝试从哪种类型进行转换。
一种选择是拥有一个所有结构都实现的
IDistance
接口。然后你可以使用:由于你已经有了一个装箱值,使用接口不会导致额外的装箱或类似的事情。每个
ToDistance
实现可能只使用隐式转换:...或者您可以使用
ToDistance
进行转换。Well, it's a matter of separating the unboxing conversion from the user-defined conversion. You want both to occur - and you have to specify the type to unbox, as well as letting the compiler know when you want a user-defined conversion. The user-defined conversion has to be picked at compile time unless you're using dynamic typing, so the compiler needs to know which type it's trying to convert from.
One option is to have an
IDistance
interface which all the structs implement. Then you could just use:As you've got a boxed value already, using an interface won't cause extra boxing or anything like that. Each
ToDistance
implementation can probably just use the implicit conversion:... or you could make the conversion use
ToDistance
.是的,这只是你必须忍受的事情之一。
如果将整数放入对象中,也会遇到同样的情况:
Yeah it's just one of those things you have to live with.
You run into the same thing if you shove an integer into an object: