КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Логический вывод обобщенных методов и типовДля упрощения создания, чтения и работы с кодом в компиляторе С# имеется логический вывод типов (type inference) при вызове обобщенных методов. Это значит, что компилятор пытается определить тип, который будет автоматически использоваться при вызове обобщенного метода. Логический вывод типов показан в следующем коде:
private static void CallingSwapUsingInference() { Int32 n1 = 1, n2 = 2; Swap(ref n1, ref n2); // Вызывает Swap<Int32>. String s1 = "Aidan"; Object s2 = "Kristin"; Swap(ref s1, ref s2); // Ошибка, невозможно вывести тип. }
В этом коде в вызовах Swap аргументы-типы не задаются с помощью знаков «меньше» и «больше». В первом вызове Swap компилятор C# сумел установить, что тип n1 и n2 — Int32, поэтому он вызвал Swap, используя аргумент типа Int32. При выполнении логического вывода типа в C# используется тип данных переменной, а не объекта, на который ссылается эта переменная. Поэтому во втором вызове Swap компилятор C# «видит», что s1 имеет тип String, а s2 — Object (хотя s2 ссылается на String). Поскольку у переменных s1 и s2 разный тип данных, компилятор не может с точностью вывести тип для аргумента-типа метода Swap и выдает ошибку:
«Error CS0411: The type arguments for method 'Program.Swap<T>(ref T, ref T)' cannot be inferred from the usage. Try specifying the type arguments explicity» «Ошибка CS0411: аргументы-типы для метода Program.Swap<T>(ref T, ref T) не могут быть выведены. Попробуйте явно задать аргументы-типы».
В типе могут определяться несколько методов так, что один из них будет принимать конкретный тип данных, а другой — обобщенный параметр-тип, как в этом примере:
private static void Display(String s) { Console.WriteLine(s); }
private static void Display<T>(T o) { Display(o.ToString()); // Вызывает Display(String). }
Метод Display можно вызвать несколькими способами:
Display("Jeff"); // Вызывает Display(String). Display(123); // Вызывает Display<T>(T). Display<String>("Aidan"); // Вызывает Display<T>(T).
В первом вызове компилятор может вызвать либо метод Display, принимающий String, либо обобщенный метод Display (заменяя T на String). Но компилятор C# всегда выбирает явное, а не обобщенное соответствие, поэтому генерирует вызов необобщенного метода Display, принимающего String. Во втором вызове компилятор не может вызвать необобщенный метод Display, принимающий String, поэтому он должен вызвать обобщенный метод Display. Кстати, это очень удачно, что компилятор всегда выбирает более явное соответствие. Ведь, если бы компилятор выбрал обобщенный метод Display, тот вызвал бы ToString, возвращающий String, что привело бы к бесконечной рекурсии. Третий вызов Display задает обобщенный аргумент-тип, String. Для компилятора это означает, что вместо попытки вывести аргументы-типы он должен использовать аргументы-типы, которые указаны. В данном случае компилятор также считает, что непременно нужно вызвать обобщенный метод Display, поэтому он его и вызывает. Внутренний код обобщенного метода Display вызовет ToString для переданной ему строки, а полученная в результате строка затем передается необобщенному методу Display.
|