有没有办法在 C# 中为泛型类型的特定版本定义隐式转换运算符?
Is there a way to define implicit conversion operators in C# for specific versions of generic types?
我有一个泛型 class、MyClass<T>
,我希望能够从某种类型隐式转换,例如bool
,到通用类型的特定版本,例如MyClass<string>
。看来我不能使用以下任何一项:
失败因为"Using the generic type 'MyClass<T>' requires '1' type argument(s)":
public static implicit operator MyClass(bool value) {
return new MyClass<string>(value.ToString());
}
失败,因为 "Unbound generic name is not valid in this context" 和 "User-defined conversion must convert to or from the enclosing type":
public static implicit operator MyClass<>(bool value) {
return new MyClass<string>(value.ToString());
}
失败因为"User-defined conversion must convert to or from the enclosing type":
public static implicit operator MyClass<string>(bool value) {
return new MyClass<string>(value.ToString());
}
失败因为"Cannot implicitly convert type 'MyClass<string>' to 'MyClass<T>'":
public static implicit operator MyClass<T>(bool value) {
return new MyClass<string>(value.ToString());
}
有什么方法可以实现这一点,还是我只能在没有它的情况下生活(并且到处都会显式调用转换方法)?
不,你不能这样做。 C# 规范很明确,您的 implicit
运算符 必须 与其声明的类型相互转换。它必须是 exact 转换,并且由于声明类型恰好是 MyClass<T>
,转换必须是到或从那个转换。
参见例如Can i use a generic implicit or explicit operator? C# and 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;
}
}
上述主题有多种变体,但它们都将涉及以某种方式规避和特殊封装类型。
值得指出的是,除了此处处理通用与特定的困难之外,implicit
的使用因其他原因而受到怀疑。 The documentation 在顶部说明应该只使用 implicit
"if the conversion is guaranteed not to cause a loss of data" 和实现 "should never throw exceptions".在这两种情况下,都是 "so that they can be used safely without the programmer's awareness"。换句话说,implicit
的本质是它们被隐式调用,程序员甚至不必考虑它。所以它们必须总是工作,上面的一些例子不一定是这种情况(在一个例子中,无论如何你都必须使用显式语法,所以你也可以无论如何将运算符实现为 explicit
)。
None 这些选项是理想的。但坦率地说,原始场景也不是。通用类型必须在特定基础上处理具体类型是很奇怪的。它首先质疑泛型类型是否真的应该是泛型。您可能真的应该做一些更像上面的子类化示例的事情,只是进一步应用。 IE。将通用类型用于您需要的任何基本行为,但将所有专业化放入您知道类型参数 T
.
的子类中
鉴于问题中缺乏详细信息,我不能提供比这更多的建议。但基本要求不够稳固,足以表明,如果问题包含更广泛的问题陈述和导致您实现此实际实施目标的详细信息,则可能会提供更好、更适用的答案。
我有一个泛型 class、MyClass<T>
,我希望能够从某种类型隐式转换,例如bool
,到通用类型的特定版本,例如MyClass<string>
。看来我不能使用以下任何一项:
失败因为"Using the generic type 'MyClass<T>' requires '1' type argument(s)":
public static implicit operator MyClass(bool value) { return new MyClass<string>(value.ToString()); }
失败,因为 "Unbound generic name is not valid in this context" 和 "User-defined conversion must convert to or from the enclosing type":
public static implicit operator MyClass<>(bool value) { return new MyClass<string>(value.ToString()); }
失败因为"User-defined conversion must convert to or from the enclosing type":
public static implicit operator MyClass<string>(bool value) { return new MyClass<string>(value.ToString()); }
失败因为"Cannot implicitly convert type 'MyClass<string>' to 'MyClass<T>'":
public static implicit operator MyClass<T>(bool value) { return new MyClass<string>(value.ToString()); }
有什么方法可以实现这一点,还是我只能在没有它的情况下生活(并且到处都会显式调用转换方法)?
不,你不能这样做。 C# 规范很明确,您的 implicit
运算符 必须 与其声明的类型相互转换。它必须是 exact 转换,并且由于声明类型恰好是 MyClass<T>
,转换必须是到或从那个转换。
参见例如Can i use a generic implicit or explicit operator? C# and 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;
}
}
上述主题有多种变体,但它们都将涉及以某种方式规避和特殊封装类型。
值得指出的是,除了此处处理通用与特定的困难之外,implicit
的使用因其他原因而受到怀疑。 The documentation 在顶部说明应该只使用 implicit
"if the conversion is guaranteed not to cause a loss of data" 和实现 "should never throw exceptions".在这两种情况下,都是 "so that they can be used safely without the programmer's awareness"。换句话说,implicit
的本质是它们被隐式调用,程序员甚至不必考虑它。所以它们必须总是工作,上面的一些例子不一定是这种情况(在一个例子中,无论如何你都必须使用显式语法,所以你也可以无论如何将运算符实现为 explicit
)。
None 这些选项是理想的。但坦率地说,原始场景也不是。通用类型必须在特定基础上处理具体类型是很奇怪的。它首先质疑泛型类型是否真的应该是泛型。您可能真的应该做一些更像上面的子类化示例的事情,只是进一步应用。 IE。将通用类型用于您需要的任何基本行为,但将所有专业化放入您知道类型参数 T
.
鉴于问题中缺乏详细信息,我不能提供比这更多的建议。但基本要求不够稳固,足以表明,如果问题包含更广泛的问题陈述和导致您实现此实际实施目标的详细信息,则可能会提供更好、更适用的答案。