【问题标题】:Generic explicit cast failure C#通用显式强制转换失败 C#
【发布时间】:2012-08-13 12:16:37
【问题描述】:

以下代码有一些问题。我想为一个对象显式一个字符串,这工作得很好,但是,如果这个对象是一个泛型类的一部分,这将失败并出现以下错误异常:“无法转换类型为'System.String'的对象输入'test.B'”。即使我已经重载了该方法。

using System;
using System.Collections.Generic;

namespace test {
    class Program {
        static void Main(string [] args) {
            // These two cast perfectly fine.
            B x = (B) "abc";
            C y = (C) "def";

            A <B> a = new A<B>();
            a.b();
            A <C> b = new A<C>();
            b.b();
        }
    }

    class A<T> {
        public List <T> a = new List<T>();

        public void b() {
            // Unable to cast object of type 'System.String' to type 'test.B'
            this.a.Add ((T) (object) "abc"); 
            this.a.Add ((T) (object) "def");
            this.a.Add ((T) (object) "ghi");
        }
    }

    class B {
        public string b;

        public static explicit operator B(string a) {
            B x = new B();
            x.b = a;
            return x;
        }
    }

    class C {
        public string c;

        public static explicit operator C(string a) {
            C x = new C();
            x.c = a;
            return x;
        }
    }
}

如果有人能向我解释为什么这不能正确投射,那就太棒了。

谢谢

【问题讨论】:

    标签: c# generics casting explicit


    【解决方案1】:

    转换运算符仅适用于静态已知类型的情况;毕竟,泛型方法需要为每个T 使用完全相同的IL - 所以在某些情况下它不能调用您的运算符,而在其他情况下则不能进行类型检查。

    此外,因为您已明确转换为object,所以它永远不会被使用; object 的强制转换总是简单的拆箱或类型检查。

    一个邪恶的解决办法是(我不喜欢这样):

            this.a.Add((T)(dynamic)"abc");
            this.a.Add((T)(dynamic)"def");
            this.a.Add((T)(dynamic)"ghi");
    

    将分辨率推迟到运行时。它有效,但在那之后我需要洗眼睛。不过,更一般地说:运算符和泛型 不能很好地发挥作用 - 所以:尽量不要在您的 API 中使用这种组合。我个人真的不会使用上述内容!

    【讨论】:

    • 感谢您快速回复我的问题,非常感谢。我将尝试找到一种不同的方法,因为在对动态类型进行了一些研究之后,我同意你的观点,这根本不是最好的方法。再次感谢。
    【解决方案2】:

    如果泛型参数具有您正在使用的显式转换,编译器在编译时不知道。

    你可以引入接口,并限制泛型参数

    【讨论】:

    • 你不能在接口上放置转换操作符
    • @Marc 您可以将转换包装在一个方法中
    • 对于“转换为”方法,也许; “转换自”比较棘手(这就是问题所在)-您需要创建该类型的实例来调用创建该类型实例的方法-但是很糟糕
    • 好吧,除了在泛型参数约束中无参数之外,肯定没有其他方法可以指定构造函数,但是 where T: IMyInter,new() 约束的组合可以解决问题。
    【解决方案3】:

    您插入了 (object) 强制转换以使编译器停止告诉您您做错了。这行得通,编译器不再抱怨,因为这阻止了它检查类型。并且从 object 到 T 的转换实际上可能会起作用,只要几率很小。

    但您没想到的是,显式转换运算符是 C# 语言功能。只有编译器知道在应用这种强制转换时要执行什么方法。它不是 CLR 功能,运行时不会去寻找和收集来尝试找到适用的方法来进行转换。 C# 编译器无法使用您在编译时提供的任何运算符,它不知道 T 的类型。

    问题是,当强制转换执行时,编译器不再提供帮助。卡布姆。

    在运行时而不是编译时应用泛型类型是 .NET 的一项功能,通用术语是“具体化泛型”。与“类型擦除”相反,泛型在 Java 和 C++ 中的实现方式。类型擦除的问题在于,在编译代码后,所有关于泛型类型参数的信息都会丢失,泛型类型不能被另一种语言使用,并且反射不起作用。具体化泛型的问题在于不能普遍适用于任何类型的操作无法使用。像运算符+()。就像这个演员表一样。

    【讨论】:

      【解决方案4】:

      因为A&lt;T&gt;T 不知道BC 的显式转换运算符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多