2017-03-31 104 views
1

我有一个泛型类,MyClass<T>,我希望能够隐式转换某种类型,例如,例如bool,到通用类型的特定版本,例如, MyClass<string>。看来我不能使用任何的以下内容:有没有办法在C#中为特定版本的泛型类型定义隐式转换运算符?

  • ,因为 “使用泛型类型 'MyClass的< T>' 要求 '1' 类型的参数(S)” 失败:

    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的<字符串>’到“MyClass的< T> ““:

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

有什么办法这个可以的政绩ved,还是我只需要没有它就生活(并且在任何地方都会显式调用转换方法)?

回答

2

不,你不能这样做。 C#规范很明确,您的implicit运营商必须转换为或从其声明的类型转换。它必须是确切的转换,并且由于声明类型正好是MyClass<T>,所以转换必须是或者来自该转换。

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

在纵容或认可的XY Problem的风险,这里有几个哈克替代品:

// 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; 
    } 
} 

有一些上面的主题变化,但他们都将涉及规避和特殊外壳的以某种方式键入。

值得指出的是,除了这里处理泛型与特定难度之外,还有其他原因使用implicitThe documentation状态右侧顶部是一个应该使用implicit只有“如果转换不能保证会导致数据丢失”和实现“不应该抛出异常”。在这两种情况下,这是“,以便它们可以安全地使用,而不需要程序员的意识”。换句话说,implicit的本质就是它们被隐式调用,而程序员甚至不必考虑它。所以他们必须总是工作,上面的一些例子并不一定是这种情况(并且在一个例子中,您必须使用明确的语法,因此无论如何您都可以实现运算符为explicit)。

这些选项都不理想。但坦率地说,最初的情况也不是。泛型类型必须在具体的基础上处理具体类型是很奇怪的。它让人质疑泛型是否真的应该是通用的。有可能你真的应该做更像上面的子类化的例子,只能进一步应用。即使用泛型类型来处理需要的任何基本行为,但是将所有专业化分类放到知道类型参数T的子类中。

由于缺乏问题的细节,我不能提供更多的建议。但是基本要求不够明确,如果只有问题包含了更广泛的问题陈述和关于是什么导致您实现实际目标的细节,则可能会提供更好和更适用的答案。

+0

在隐式运算符的文档中,声明他们不应该抛出(我认为即使没有文档,也很清楚它有多糟糕:)) – Evk

+0

@Evk:是的,我同意这个建议。如果保证转换不会导致数据丢失,文档还说只使用'implicit'“_,这也是一个很好的建议。但是OP明确地(抱歉)要求'implicit'的帮助,并且当提供一个没有支持转换的'T'类型时,我没有看到一个很好的替代方法来抛出异常。也就是说,我认为值得在我的回答中提及这些问题,所以谢谢提醒。 –

+0

感谢您的回答,@Peter。我曾想过你提出的两种可能性;但是,他们都不能满足我的需求,因为我不能真正使用它们。你是什​​么意思“虽然有可能在一些运行时使用表达式的时候,你可以缓存一个能够在没有装箱的情况下处理转换的代理”? – Tom

相关问题