КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Использование переменных обобщенного типа в качестве операндов⇐ ПредыдущаяСтр 53 из 53 И, наконец, замечу, что немало трудностей несет в себе использование операторов с операндами обобщенного типа. C# умеет интерпретировать операторы (например +, -, * и /), применяемые к элементарным типам. Но эти операторы нельзя использовать с переменными обобщенного типа, потому что во время компиляции компилятор не знает их тип. Получается, что вы не сможете написать математический алгоритм для произвольных числовых типов данных. Я написал следующий обобщенный метод.
private static T Sum<T>(T num) where T : struct { T sum = default(T); for (T n = default(T); n < num; n++) sum += n; return sum; }
Я также сделал все возможное, чтобы он скомпилировался: определил ограничение struct для T и использовал default(T), чтобы sum и n инициализировались нулем. Но при компиляции кода появились три сообщения об ошибке: 1. ошибка CS0019: оператор «<» нельзя применять к операндам типа T и T 2. ошибка CS0023: оператор «++» нельзя применять к операнду типа T 3. ошибка CS0019: оператор «+=» нельзя применять к операндам типа T и T Это существенно ограничивает поддержку обобщений в CLR-среде, и многие разработчики испытали глубокое разочарование. Многие пытались создать методы, призванные обойти это ограничение с помощью отражения (главу глава 22), перегрузку оператора и т. п. Но все эти решения сильно снижают производительность или ухудшают читабельность кода. ===================== Общие (или параметризованные) типы (generics) позволяют при описании классов, структур, методов и интерфейсов использовать параметризованные параметры (не указывать тип параметра в момент написания кода). Тип параметра определяется в момент объявления переменной соответствующего типа. Таким образом можно создать некоторый общий элемент, тип который можно использовать в дальнейшем для данных различных типов. Программисты на C++ могут углядеть с общих типах сходство с шаблонами (templates), в чем-то эта аналогия будет верна, но тут существуют некоторые ограничения. Создадим класс, используя общие типы: class Generics<TYPE1, TYPE2> { private TYPE1 mVar1; private TYPE2 mVar2; public Generics(TYPE1 Var1, TYPE2 Var2) { this.mVar1 = Var1; this.mVar2 = Var2; } public string ToStringFunction(string Delemiter) { return this.mVar1.ToString() + Delemiter + this.mVar2.ToString(); } public TYPE1 Variable1 { get { return this.mVar1; } set { this.mVar1 = value; } } public TYPE2 Variable2 { get { return this.mVar2; } set { this.mVar2 = value; } } }
Как видно из примера, для того чтобы использовать общие типы нужно после объявления класса указать параметризованные типы: Generics<TYPE1, TYPE2> объявляет класс с двумя параметризованными типами. Теперь используем написанный класс:
// объявление Generics<string, string> strGeneric = new Generics<string, string>("Hello", "world"); Generics<int, int> intGeneric = new Generics<int, int>(1, 2); Generics<string, int> strintGeneric = new Generics<string, int>("Three", 3); int intSum; string strSum; // использование intSum = intGeneric.Variable1 + intGeneric.Variable2; strSum = strintGeneric.Variable1 + " " + strintGeneric.Variable2.ToString(); MessageBox.Show("\nstrGeneric:\n" + strGeneric.Variable1 + " " + strGeneric.Variable2 + "\n\nintGeneric sum:\n" + intSum.ToString() + "\n\nstrintGeneric sum:\n" + strSum.ToString());
Таким образом, очевидно, что создан класс который можно использовать с параметрами различных типов, которые устанавливаются в момент объявления класса. Аналогичным образом можно объявить структуру или интерфейс:
public struct GenericStruct<TYPE> { public TYPE someField; } public interface IGeneric<TYPE> { TYPE SomeMethod(); TYPE AnotherMethod(); }
Более того, параметризованные типы могут быть использованы при объявлении делегатов функций. Продемонстрирую эту возможность используя объявленный выше класс Generics.
// Объявляем делегат public delegate DELEGATETYPE GenericDelegate<DELEGATETYPE, PARAMTYPE> (PARAMTYPE Param); // используем делегат Generics<string, string> strGeneric = new Generics<string, string>("Hello", "world"); GenericDelegate<string, string> genDelegate = new GenericDelegate<string, string>(strGeneric.ToStringFunction); // вызов делагата MessageBox.Show(genDelegate(" my "));
|