有没有办法在C#中为特定版本的泛型类型定义隐式转换运算符?

时间:2017-03-31 23:45:03

标签: c# generics implicit-conversion

我有一个通用类MyClass<T>,我希望能够从某种类型隐式转换,例如bool,对于通用类型的特定版本,例如MyClass<string>。我似乎无法使用以下任何一种方法:

  • 失败,因为“使用泛型类型'MyClass&lt; T&gt;'需要'1'类型参数“:

    public static implicit operator MyClass(bool value) { return new MyClass<string>(value.ToString()); }

  • 失败,因为“未绑定的通用名称在此上下文中无效”,并且因为“用户定义的转换必须转换为封闭类型或从封闭类型转换”:

    public static implicit operator MyClass<>(bool value) { return new MyClass<string>(value.ToString()); }

  • 失败,因为“用户定义的转换必须转换为封闭类型或来自封闭类型”:

    public static implicit operator MyClass<string>(bool value) { return new MyClass<string>(value.ToString()); }

  • 失败,因为“无法隐式转换类型'MyClass&lt; string&gt;'到'MyClass&lt; T&gt;'“:

    public static implicit operator MyClass<T>(bool value) { return new MyClass<string>(value.ToString()); }

有没有办法实现这一目标,或者我是否必须在没有它的情况下生活(并且在任何地方都会明确调用转换方法)?

1 个答案:

答案 0 :(得分:3)

不,你不能这样做。 C#规范很明确,您的implicit运算符必须转换为其声明的类型或从其声明的类型转换。它必须是完全转换,并且由于声明类型正好是MyClass<T>,因此转换必须是或来自该转换。

参见例如Can i use a generic implicit or explicit operator? C#C# Implicit operator with generic

冒着宽恕或赞同XY Problem的风险,这里有几个hacky替代方案:

// Break generics by checking the type explicitly. Requires ugly casting
// and intermediate boxing, though it's possible that with some run-time
// use of Expressions, you could cache a delegate that would handle the
// conversion without the boxing. It'd still be ugly though.
class Class1<T>
{
    public Class1(T t) { }

    public static implicit operator Class1<T>(bool value)
    {
        if (typeof(T) == typeof(string))
        {
            return (Class1<T>)(object)(Class1OfString)value;
        }

        throw new InvalidOperationException("Invalid type T");
    }
}

// Subclass the generic, and declare the conversion there. Of course, then
// to use the conversion, you have to reference this type explicitly. Ugly.
class Class1OfString : Class1<string>
{
    public Class1OfString(string text) : base(text) { }

    public static implicit operator Class1OfString(bool value)
    {
        return new Class1OfString(value.ToString());
    }
}

class A
{
    public static void M()
    {
        // These all compile and execute fine
        Class1OfString c1 = true;
        Class1<string> c2 = (Class1OfString)true;
        Class1<string> c3 = true;
    }
}

上面的主题有很多变化,但它们都涉及规避和特殊包装类型。

值得指出的是,除了处理泛型与特定的困难之外,implicit的使用还有其他原因。 The documentation在顶部指出应该仅使用implicit &#34;如果保证转换不会导致数据丢失&#34; 和实现&#34;不应该抛出异常&#34; 。在这两种情况下,这都是&#34;因此可以安全地使用它们而无需程序员的意识&#34; 。换句话说,implicit的本质是它们被隐式调用,而程序员甚至不必考虑它。因此,他们必须始终工作,这不一定是上述一些示例的情况(在一个示例中,您无论如何都必须使用显式语法,因此您不妨实现无论如何,运营商为explicit

这些选项都不是理想选择。但坦率地说,原始情景也不是。泛型类型必须在特定的基础上处理具体类型,这很奇怪。它质疑泛型类型是否真的应该是通用的。您可能真的应该做更像上面的子类化示例,只进一步应用。即将泛型类型用于您需要的任何基本行为,但将所有特化都放入一个您知道类型参数T的子类中。

鉴于问题中缺乏细节,我无法提供更多建议。但基本要求不足以表明,如果只有问题包含更广泛的问题陈述以及导致您实现这一实际目标的详细信息,则可能会提供更好,更适用的答案。