如何在 C# 中直接键入强制转换装箱结构?

发布于 2024-09-28 03:47:46 字数 1653 浏览 6 评论 0原文

我有一个结构体的命名空间,它代表各种测量单位(米、英尺、英寸等)...总共 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

审判长 2024-10-05 03:47:46

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

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

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

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

public Distance ToDistance()
{
    return this;
}

...或者您可以使用 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:

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

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:

public Distance ToDistance()
{
    return this;
}

... or you could make the conversion use ToDistance.

半﹌身腐败 2024-10-05 03:47:46

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

如果将整数放入对象中,也会遇到同样的情况:

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

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:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文