2015-09-29 1 views
1

Я не уверен, что я использую здесь правильные условия. Но я просто думаю, если есть какая-то существенная разница между assignment compatibility и type constraints. Позвольте мне объяснить это с кодом:Разница между совместимостью назначений и ограничениями типов в C#?

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 {} 

Из кода выше, есть ли разница между Test и Test2? Я могу назвать оба Test и Test2 с A или любым из его производных типов (B and C). Но как они отличаются от компилятора? Метод 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(); 
    } 
} 

Все просто распечатывается A. Может ли кто-то пролить свет на это, почему вы используете один над другим?

+0

С функциональной точки зрения, я могу» Подумайте о том, как ваши два примера будут отличаться. Тем не менее, имейте в виду, что вы можете применить ноль, одно или несколько ограничений к одному и тому же параметру общего типа, и есть несколько, которые не относятся к определенному базовому классу или интерфейсу. – jmcilhinney

+0

В дополнение к ответам ниже, еще один незначительный оттенок разницы, потенциально заслуживающий внимания, сравнивающий эти два. Если 'A' - это интерфейс, а' B' или 'C' - это структура, то вызов общего метода с общим параметром, введенным в« B »или« C »(не' A'), будет избегать операции бокса. Вызов метода «Test (A a)» с помощью структуры «B» или «C» приведет к операции по боксу. –

ответ

2

Да, родовое сохраняет тип. Это легче увидеть, если метод действительно просто повторяет параметр:

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. 

На второй половине вас сэмплирует пытаюсь сделать отправку по типу - вызов методов решил статический во время компиляции - так как компилятор знает, что T находится не менее A (но может быть равен A) он должен выбрать void O(A a).

Если вы едете из C++ мира это существенная разница между шаблонами - в отличие от C++, где шаблоны, скомпилированные для заданных типов, шаблоны C# компилируется отдельно от использования для конкретных типов - What are the differences between Generics in C# and Java... and Templates in C++?

+0

Спасибо. Очень круто. – Shivam

0

Когда вы определяете общий класс, вы можете применять ограничения на типы типов, которые клиентский код может использовать для аргументов типа, когда он создает экземпляр вашего класса. Если код клиента пытается создать экземпляр вашего класса, используя тип, который не допускается ограничением, результатом является ошибка времени компиляции.

Зачем использовать типы ограничений? Ans: Если вы хотите изучить элемент в общем списке, чтобы определить, является ли он действительным или сравнивать его с каким-либо другим элементом, компилятор должен иметь некоторую гарантию того, что оператор или метод, который он должен вызывать, будут поддерживаться любым типом аргумент, который может быть указан кодом клиента. Эта гарантия получается путем применения одного или нескольких ограничений к определению вашего общего класса. Например, ограничение базового класса сообщает компилятору, что в качестве аргументов типа будут использоваться только объекты этого типа или производные от этого типа. После того, как у компилятора есть эта гарантия, он может разрешить методы такого типа в универсальном классе.

Вы можете найти более подробную информацию здесь: https://msdn.microsoft.com/en-us/library/d5x73970.aspx

Смежные вопросы