我有一个测试类:
class Test
{
void x(ref byte v) { }
void x(ref sbyte v) { }
void x<T>(ref T[] a) where T: byte, sbyte
{
for (int i = 0; i < a.Length; ++i)
x(ref a[i]);
}
}
在错误列表窗口中,我收到错误
“参数1:无法在
ref T
行上从x(ref a[I]);
转换为'ref byte'”
Intellisense也在行上显示不同的消息:“'Test.x(ref byte)'的最佳重载方法匹配'有一些无效的参数”。有什么想法吗?
我尝试这样做,而不是为每个数组类型编写显式重载,因为我的实际代码对于'标量'类型有大约20个不同的“x”例程,而我不想要20多个函数。
好的调用多个约束是'anded',而不是'orored',但是我得到了没有约束的相同错误。
我理解为什么不需要第三次重载中的'ref',但是这个接口最终可能会重新分配数组,然后需要一个ref。
顺便说一句:我是否正确地认为“struct”的约束将与任何ValueType匹配,包括原始类型?
以下是现在的代码,但错误相同:
class Test
{
void x(ref byte v) { }
void x(ref sbyte v) { }
void x<T>(T[] a)
{
for (int i = 0; i < a.Length; ++i)
x(ref a[i]);
}
}
答案 0 :(得分:1)
roslyn给出的确切错误消息是:
(8,34,8,38): Error CS0701: 'byte' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
(8,40,8,45): Error CS0701: 'sbyte' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
(11,18,11,22): Error CS1503: Argument 1: cannot convert from 'ref T' to 'ref byte'
byte
和sbyte
不是通用参数的有效约束。在C#中,您只能使用BaseClass,Interface,引用类型,值类型和new()约束。
阅读this MSDN article,解释如何使用通用参数约束。
对于真正感兴趣的第三个编译消息是由编译器生成的,因为它试图通过忽略参数T
上的无效约束来从错误中恢复。没有任何约束,将T用作byte
是不安全的。
答案 1 :(得分:0)
这里的问题是你从一个通用方法调用非泛型方法并将一个参数T传递给该调用。为了做到这一点,你需要你的内部调用来调用xElement<T>
方法(我这样命名,因为你已经使用名称x
来整体处理数组,而你的其他方法处理一个仅限数组的元素)。但是你回到了方形1,因为你现在需要在内部方法体中有一个控制流语句(比如switch),这是你想要避免的。
这里真正的问题是模板和泛型不是一回事。第一个告诉编译器为编译时实际检测到的每个类型创建方法的副本。第二个告诉运行时根据遇到的类型找到(或JIT-compile,如果使用反射)方法的一个版本。由于您只为字节和字节提供(固定的,非通用的)版本,编译器立即知道它无法处理它在运行时可能遇到的“通用”情况。
更简洁的是,在这个用例中,是的,你将需要一个switch语句,因为你试图使用它的真正模板是不可用的。
还有另一种选择,顺便说一下,你可以自己使用反射来找到方法:
typeof(Test)
// Get all public instance methods
.GetMethods(BindingFlags.Public|
BindingFlags.Instance|
BindingFlags.DeclaredOnly)
// Search by name and by parameter type
.Where(mi => mi.Name == "xElement" &&
mi.GetParameters()[0].ParameterType = typeof(T))
// Take the first one found
.First()
// Call it
.Invoke(this, new object[] { a[i] });