C# 通用方法是';选择最具体的构造函数签名?
当我使用带有泛型参数的方法创建另一个对象时,泛型对象没有选择最具体的构造函数。这听起来很混乱,所以这里有一些示例代码来演示我的意思 有人能解释为什么这个程序的输出是: <代码> GuIDC# 通用方法是';选择最具体的构造函数签名?,c#,generics,C#,Generics,当我使用带有泛型参数的方法创建另一个对象时,泛型对象没有选择最具体的构造函数。这听起来很混乱,所以这里有一些示例代码来演示我的意思 有人能解释为什么这个程序的输出是: GuID C++中的泛型与C++模板不一样,它们在编译时不会根据使用情况而扩展。创建一个方法,并静态解析从其中调用的方法 因此,在Add中,v可以是任何类型,因此唯一已知的是它继承自object,因此C的object构造函数是唯一的候选对象 要获得您想要的行为,您必须添加另一个超负荷的add,例如 public void Add
C++中的泛型与C++模板不一样,它们在编译时不会根据使用情况而扩展。创建一个方法,并静态解析从其中调用的方法
因此,在Add
中,v
可以是任何类型,因此唯一已知的是它继承自object
,因此C
的object
构造函数是唯一的候选对象
要获得您想要的行为,您必须添加另一个超负荷的add
,例如
public void Add(Guid g) { cs.Add(new C(g)); }
重载解析在编译时完成,而不是在运行时完成。因此,当您从
Add
方法调用newc(v)
时,编译器不知道t
实际上是Guid
,因此它使用唯一保证兼容的重载,即public(object C)Lee和Thomas的答案是正确的。为了增加它们,我相信向泛型添加约束可能会使它能够选择最具体的一个。重写Add方法:
public void Add<T>(T v) where T : Guid {
cs.Add(new C(v));
}
public void Add(tv)其中T:Guid{
增加(新的C(v));
}
当然,现在只能使用Guid或Guid的扩展名调用Add。回想起来有点毫无意义。我想对于您要查找的内容,您应该进行运行时检查如果(v是Guid)
我想……对不起,我忘记了C#type check操作符是什么了。如果定义一个类Foo,其中T:SomeClass
,所有方法绑定和操作符重载都会像T
wasSomeClass
一样执行;在没有约束的情况下,它们通常会像对象一样执行。在评估绑定和重载时,不存在可以考虑T
类型的机制。
如果需要一些特殊行为的类型,可以使用一个或多个方法定义一个私有泛型接口,以对类型T
执行操作,这是一个以“通常”方式实现该接口的私有泛型类,以及私有的非泛型类,它们以适合于特定应用程序的方式实现接口“特殊类型。私有泛型类应该持有对接口类型的静态引用。对于非特殊类T
,该引用应引用私有泛型类的实例。对于特殊类型,该引用应引用“特殊”类的实例。在执行可能是“特殊”的方法时,使用此方法将需要额外级别的虚拟调度,但将避免基于T
的其他运行时类型检查,我建议您将代码设置为如下:
void Main()
{
B b = new B();
C c = new C(Guid.Empty);
b.Add<Guid>(Guid.Empty);
}
public class B
{
List<C> cs = new List<C>();
public void Add<T>(T v) { cs.Add(new C(v)); }
}
public class C<T>
{
public C(T c)
{
if(c is Guid)
{
Console.WriteLine("guid"); }
}else{
Console.WriteLine("object");
}
}
}
void Main()
{
B=新的B();
C=新的C(Guid.Empty);
b、 添加(Guid.Empty);
}
公共B级
{
List cs=新列表();
公共无效添加(tv){cs.Add(新的C(v));}
}
公共C类
{
公共电话(TC)
{
if(c是Guid)
{
Console.WriteLine(“guid”);}
}否则{
控制台。写入线(“对象”);
}
}
}
这个版本应该可以编译,注意您必须手动检查泛型的类型
编辑:
由于列表的原因,这实际上无法编译:
List<C> cs = new List<C>();
List cs=new List();
不可能以类型安全的方式表示代码。您的选择是重新构造其工作方式,或者从C
构造函数中的object
进行手动强制转换(或者可能查看dynamic
是否符合您的需要)是否按类进行?因为我看了这个,我知道T
是一个Guid
,因为b.Add(…)
。但是如果是基于每个类,那么我可以理解,因为B
类可能在预编译的DLL中。这听起来像是我理解吗?如果这是C++模板,那么在编译时生成特定类型的代码会调用更具体的重写吗?@ MichaelBray,是的,实际上,对于泛型方法,它是按每个方法进行的。编译Add
方法时,编译器不会查看它的调用方式,只会查看方法本身。@thomasleveque:aha。。。我通过删除重载构造函数C(object C)
对此进行了测试,果然,它不再编译,抱怨它无法从't'转换为'System.Guid'
。这是有道理的。这里的教训是:C++不是C++,泛型不是模板。泛型是类型系统的一部分,类型系统是一个逻辑框架,编译器在其中对源代码的含义进行逻辑推断。模板更像是一个词汇系统;你可以将模板实例化想象为简单地替换文本,然后从头开始分析新文本。这甚至不需要编译-Guid不是有效的泛型类型约束。是的,我不认为我意识到Guid是一个结构,而不是一个类。强制特定结构的泛型定义将…根本不是泛型。对不起,那没用。