Модификация обобщенных методов
Переопределение виртуальных методов в обобщенном классе
В обобщенном классе виртуальный метод может быть переопределен таким же образом, как и любой другой метод. В качестве примера рассмотрим следующую программу, в которой переопределяется виртуальныe методы GetObj() и ToString():
using System; namespace ConsoleApplication1 { class MyClass<T> { protected T obj; public MyClass(T ob) { obj = ob; } public virtual T GetObj() { Console.WriteLine("Значение объекта: " + obj); return obj; } } class InfoObject<T> : MyClass<T> { public InfoObject(T ob) : base(ob) { } // Переопределим методы базового класса public override T GetObj() { return base.GetObj(); } // Переопределим встроенный метод ToString public override string ToString() { return String.Format("Тип объекта: {0}",typeof(T)); } } class Program { static void Main() { InfoObject<int> i = new InfoObject<int>(10); i.GetObj(); Console.WriteLine(i.ToString()); Console.ReadLine(); } } }
Перегрузка методов с несколькими параметрами типа
Методы, параметры которых объявляются с помощью параметров типа, могут быть перегружены. Но правила их перегрузки упрощаются по сравнению с методами без параметров типа. Как правило, метод, в котором параметр типа служит для указания типа данных параметра этого метода, может быть перегружен при условии, что сигнатуры обоих его вариантов отличаются. Это означает, что оба варианта перегружаемого метода должны отличаться по типу или количеству их параметров. Но типовые различия должны определяться не по параметру обобщенного типа, а исходя из аргумента типа, подставляемого вместо параметра типа при конструировании объекта этого типа. Следовательно, метод с параметрами типа может быть перегружен таким образом, что он окажется пригодным не для всех возможных случаев, хотя и будет выглядеть верно.
В качестве примера рассмотрим следующий обобщенный класс:
// Пример неоднозначности, к которой может привести // перегрузка методов с параметрами типа. // // Этот код не подлежит компиляции, using System; // Обобщенный класс, содержащий метод Set(), перегрузка // которого может привести к неоднозначности, class Gen<T, V> { T ob1; V ob2; // ... // В некоторых случаях эти два метода не будут // отличаться своими параметрами типа, public void Set(Т о) { ob1 = о; } public void Set(V о) { ob2 = о; } class AmbiguityDemo { static void Main() { Gen<int, double> ok = new Gen<int, double>(); Gen<int, int> notOK = new Gen<int, int>(); ok.Set(lO); // верно, поскольку аргументы типа отличаются notOK.Set(10); // неоднозначно, поскольку аргументы ничем не отличаются! } }
Рассмотрим приведенный выше код более подробно. Прежде всего обратите внимание на то, что класс Gen объявляется с двумя параметрами типа: T и V. В классе Gen метод Set() перегружается по параметрам типа T и V.
Такой подход кажется вполне обоснованным, поскольку типы T и V ничем внешне не отличаются. Но подобная перегрузка таит в себе потенциальную неоднозначность. При таком объявлении класса Gen не соблюдается никаких требований к различению типов T и V. Например, нет ничего принципиально неправильного в том, что объект класса Gen будет сконструирован так, как показано ниже:
Gen<int, int> notOK = new Gen<int, int>();
В данном случае оба типа, T и V, заменяются типом int. В итоге оба варианта метода Set() оказываются совершенно одинаковыми, что, разумеется, приводит к ошибке. Следовательно, при последующей попытке вызвать метод Set() для объекта notOK в методе Main() появится сообщение об ошибке вследствие неоднозначности во время компиляции.
Как правило, методы с параметрами типа перегружаются при условии, что объект конструируемого типа не приводит к конфликту. Следует, однако, иметь в виду, что ограничения на типы не учитываются при разрешении конфликтов, возникающих при перегрузке методов. Поэтому ограничения на типы нельзя использовать для исключения неоднозначности. Конструкторы, операторы и индексаторы с параметрами типа могут быть перегружены аналогично конструкторам по тем же самым правилам.
Комментарии