通用方法是不是选择最具体的构造函数签名?

时间:2013-07-16 18:42:23

标签: c# generics

当我使用带有泛型参数的方法来创建另一个对象时,泛型对象不会选择最具体的构造函数。这听起来令人困惑,所以这里有一些示例代码来证明我的意思......

任何人都可以解释为什么这个程序的输出是:

guid    <-- easy - no problem here
object  <-- WHY?  This should also be "guid"?!

...以及如何使通用Add<T>函数调用C的正确构造函数?这是代码:

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
{
    public C(Guid c) { Console.WriteLine("guid"); }
    public C(object c) { Console.WriteLine("object"); }
}

5 个答案:

答案 0 :(得分:10)

重载解析在编译时完成,而不是在运行时。因此,当您从new C(v)方法调用Add<T>时,编译器不知道T实际上将是Guid,因此它使用唯一保证为的重载兼容,即public C(object c)

答案 1 :(得分:3)

C#中的泛型与C ++模板的工作方式不同 - 它们在编译时不会根据用法进行扩展。创建一个方法,静态解析从中调用的方法。

因此,在Add中,v可以是任何类型,因此唯一已知的是继承自object所以object的{​​{1}}构造函数是唯一的候选人。

要获得您想要的行为,您必须添加C的另一个重载,例如

Add

答案 2 :(得分:0)

李和托马斯的答案是正确的。要添加它们,我相信为您的泛型添加约束可能使其能够选择最具体的一个。重写Add方法:

public void Add<T>(T v) where T : Guid {
  cs.Add(new C(v));
}

当然,现在您只能使用Guid或Guid的扩展名来调用Add。回想起来有点毫无意义。我想你正在寻找什么,你会做一个运行时检查。 if (v is Guid)我想......对不起,我忘记了C#类型检查操作符是什么。

答案 3 :(得分:0)

如果定义了一个类Foo<T> where T:SomeClass,则将执行所有方法绑定和运算符重载,就像TSomeClass一样;在没有约束的情况下,它们通常会像Object那样执行。在评估绑定和重载时,没有机制可以考虑T的类型。

如果需要有一些特殊行为的类型,可以使用一个或多个方法定义一个私有泛型接口,以对类型T执行操作,这是一个私有泛型类,它在“通常的“时尚和私有非泛型类,它们以适合某些特殊类型的方式实现接口。私有泛型类应该包含对接口类型的静态引用。对于非特殊类T,该引用应该引用私有泛型类的一个实例。对于特殊类型,该引用应该引用“特殊”类的一个实例。使用这种方法在执行一个方法时可能需要额外的虚拟分派级别。特殊的“,但将避免需要基于T的其他运行时类型检查。

答案 4 :(得分:0)

我建议你的代码是这样的:

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");
        }
    }
}

这个版本应该编译,注意你必须手动检查通用的类型,但

编辑:

由于列表实际上无法编译:

List<C> cs = new List<C>();

无法以类型安全的方式表示您的代码。您的选择是重新调整其工作方式或从object构造函数中C进行手动转换(或者可能看看dynamic是否符合您的需求)