简体   繁体   English

C#中的分配兼容性和类型约束之间的区别?

[英]Difference between assignment compatibility and type constraints in C#?

I'm not sure if I'm using the right terms here. 我不确定在这里使用的术语是否正确。 But I'm just thinking, if there is any major difference between assignment compatibility and type constraints . 但是我只是在想, assignment compatibilitytype constraints之间是否有重大区别。 Let me explain it with code: 让我用代码解释一下:

public class A {}
public class B : A {}
public class C : A {}


public static void Test(A a){}
public static void Test2<T>(T a) where T : A {}

From code above, is there any difference between Test and Test2 ? 从上面的代码, TestTest2之间有什么区别吗? I can call both Test and Test2 with A or any of its derived types ( B and C ). 我可以使用A或其任何派生类型( B and C )来调用TestTest2 But, how are they different to compiler? 但是,它们与编译器有何不同? Does generic method somehow preserves the type such that if I call it with B it will not cast it to A , I tried experimenting with overload resolution but there seems to be no difference, please see my experiment with overload resolutions. generic方法是否以某种方式保留了类型,如果我用B调用它不会将其强制转换为A ,我尝试使用重载分辨率进行实验,但似乎没有什么区别,请参阅重载分辨率的实验。

class Program
{
    public class A {}
    public class B : A {}
    public class C : A {}

    public static void Test(A a) { O(a); }
    public static void Test2<T>(T a) where T : A { O(a); }

    public static void O(A a) { Console.WriteLine("A"); }
    public static void O(B a) { Console.WriteLine("B"); }
    public static void O(C a) { Console.WriteLine("C"); }

    static void Main(string[] args)
    {
        Test2<A>(new A());
        Test2<B>(new B());
        Test2<C>(new C());
        Test(new A());
        Test(new B());
        Test(new C());
        Console.Read();
    }
}

Everything just prints out A . 一切都打印出A Can someone shed light on this, why would you use one over other? 有人可以阐明这一点吗,为什么您要使用另一个?

Yes, generic preserves the type. 是的,泛型保留类型。 It is easier to see if method actually simply echoes parameter: 更容易看出方法是否实际上只是回显参数:

public class A 
{
   public string Question {get;set;}
}
public class B : A 
{ 
    public string Answer {get;set;}
}

T Echo<T>(T arg) where T : A 
{
   Console.WriteLine(arg.Question); // we know arg is at least "A"
   return arg;
}

var a = new A {Question = "Q1"};
var b = new B {Question = "Q2"};

Echo(a); // result is of type A
Echo(b).Answer = "42"; // result is of type B - can use "Asnwer"
Echo(3); // Compile error 3 is not A.

On second half of you sample with trying to do dispatch by type - invocation of methods decided statically at compile time - since compiler only knows that T is at least A (but can be equal to A ) it has to pick void O(A a) . 在您的第二部分中,尝试按类型进行分派-调用在编译时静态确定的方法-由于编译器仅知道T至少为A (但可以等于A ),因此必须选择void O(A a)

If you are coming from C++ world this is significant difference between templates - unlike C++ where templates compiled for given types, C# templates are compiled separately from usage for particular types - What are the differences between Generics in C# and Java... and Templates in C++? 如果您来自C ++世界,这是模板之间的显着差异-与C ++不同,在C ++中,模板是为给定类型编译的,C#模板是与特定类型的用法分开编译的-C#和Java中的泛型之间有什么区别? C ++?

When you define a generic class, you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class. 定义通用类时,可以对实例化类时客户端代码可用于类型参数的类型类型施加限制。 If client code tries to instantiate your class by using a type that is not allowed by a constraint, the result is a compile-time error. 如果客户端代码尝试使用约束不允许的类型实例化您的类,则结果是编译时错误。

Why using the Constraint types? 为什么要使用约束类型? Ans: If you want to examine an item in a generic list to determine whether it is valid or to compare it to some other item, the compiler must have some guarantee that the operator or method it has to call will be supported by any type argument that might be specified by client code. 回答:如果要检查通用列表中的项目以确定其是否有效或将其与其他项目进行比较,则编译器必须保证所有类型参数都支持它必须调用的运算符或方法。可能由客户端代码指定。 This guarantee is obtained by applying one or more constraints to your generic class definition. 通过对您的通用类定义应用一个或多个约束来获得此保证。 For example, the base class constraint tells the compiler that only objects of this type or derived from this type will be used as type arguments. 例如,基类约束告诉编译器,只有此类型的对象或从该类型派生的对象将用作类型参数。 Once the compiler has this guarantee, it can allow methods of that type to be called in the generic class. 编译器获得此保证后,便可以允许在通用类中调用该类型的方法。

You can find more info here: https://msdn.microsoft.com/en-us/library/d5x73970.aspx 您可以在这里找到更多信息: https : //msdn.microsoft.com/en-us/library/d5x73970.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM