Generics in C# BG

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 8

Щаблонни класове(generics) in C#

1. Необходимост от шаблонни класове и методи


Нека разберем необходимостта от шаблонни класове в C# с един пример. Нека
създадем проста програма, за да проверим дали две цели числа са равни или не.
Създават се два класа ClsCalculator и ClsMain. В класа ClsCalculator имаме метод
AreEqual(), който приема две цели числа като входни параметри и след това
проверява дали двете входни стойности са равни или не. Ако и двете са равни,
тогава той връща true, иначе ще върне false. И от класа ClsMain се извиква
статичния метод AreEqual() и се показва изхода въз основа на върнатата стойност.

Програма 1а
namespace GenericsDemo
{
public class ClsMain
{
private static void Main()
{
bool IsEqual = ClsCalculator.AreEqual(10, 20);
if (IsEqual)
{
Console.WriteLine("Both are Equal");
}
else
{
Console.WriteLine("Both are Not Equal");
}
Console.ReadKey();
}
}
public class ClsCalculator
{
public static bool AreEqual(int value1, int value2)
{
return value1 == value2;
}
}
}

В горния пример, ако се опитаме да предадем стойности, различни от


целочислените, тогава ще получим грешка по време на компилиране. Това е така,
защото методът AreEqual() на класа ClsCalculator е тясно ограничен с целочисления
тип данни и следователно не е възможно да се извика методът AreEqual, различен от
стойностите на целочисления тип данни. Така че, когато се опитаме да извикаме
метода AreEqual() чрез предаване на низови стойности, както е показано по-долу,
получаваме грешка по време на компилиране.
bool Equal = ClsCalculator.AreEqual(“ABC”, “XYZ”);
Един от начините да накараме горния метод AreEqual() да приема стойности на
низови типове, както и стойности на целочислен тип, трябва да използваме обектния
тип данни като параметри. Ако направим параметрите на метода AreEqual() от тип
обект, тогава той ще работи с всеки тип данни.
Забележка: Най-важният момент, който трябва да запомните, е всеки .NET тип
данни, независимо дали е примитивен тип референтен тип, пряко или косвено
наследява типа данни System.Object.

[Дата]
1
2. Промяна на метод за да приема различни типове данни
Нека модифицираме метода AreEqual() на класа ClsCalculator, за да използваме
типа данни Object, както е показано по-долу
Програма 1б
namespace GenericsDemo
{
public class ClsMain
{
private static void Main()
{
// bool IsEqual = ClsCalculator.AreEqual(10, 20);
bool IsEqual = ClsCalculator.AreEqual("ABC", "ABC");
if (IsEqual)
{
Console.WriteLine("Both are Equal");
}
else
{
Console.WriteLine("Both are Not Equal");
}
Console.ReadKey();
}
}
public class ClsCalculator
{
//Now this method can accept any data type
public static bool AreEqual(object value1, object value2)
{
return value1 == value2;
}
}
}
Недостатъци:

1. Затруднения поради опаковане и разопаковане. Типът обект трябва да бъде


преобразуван в тип стойност.
2. Сега методът AreEqual() не е обезопасен по отношение на тип. Възможно е да
се предаде низова стойност за първия параметър и целочислена стойност за
втория параметър.

Постигане на същия резултат с предефиниране на методи


Друга възможност е предефиниране на метода AreEqual(), който ще приема
различни типове параметри, както е показано по-долу. Създават се три метода със
същото име, но с различни типове параметри.

Програма 2
namespace GenericsDemo
{
public class ClsMain
{
private static void Main()
{
// bool IsEqual = ClsCalculator.AreEqual(10, 20);
// bool IsEqual = ClsCalculator.AreEqual("ABC", "ABC");
bool IsEqual = ClsCalculator.AreEqual(10.5, 20.5);

[Дата]
2
if (IsEqual)
{
Console.WriteLine("Both are Equal");
}
else
{
Console.WriteLine("Both are Not Equal");
}
Console.ReadKey();
}
}
public class ClsCalculator
{
public static bool AreEqual(int value1, int value2)
{
return value1 == value2;
}
public static bool AreEqual(string value1, string value2)
{
return value1 == value2;
}
public static bool AreEqual(double value1, double value2)
{
return value1 == value2;
}}
}

Проблемът с горната реализация на кода е, че ние повтаряме една и съща логика


във всеки метод. Въпреки това, ако утре трябва да сравним две float или две long
стойности, тогава трябва да създадем още два метода.

3. Решаване на всички посочени до тук проблеми


Можем да решим всички горепосочени проблеми, като използваме шаблонни
класове и методи.
Програма 3
namespace GenericsDemo
{
public class ClsMain
{
private static void Main()
{
//bool IsEqual = ClsCalculator.AreEqual<int>(10, 20);
//bool IsEqual = ClsCalculator.AreEqual<string>("ABC", "ABC");
bool IsEqual = ClsCalculator.AreEqual<double>(10.5, 20.5);
if (IsEqual)
{
Console.WriteLine("Both are Equal");
}
else
{
Console.WriteLine("Both are Not Equal");
}
Console.ReadKey();
}}

public class ClsCalculator


{
public static bool AreEqual<T>(T value1, T value2)
{
return value1.Equals(value2); }}}

[Дата]
3
За да направим метода AreEqual() шаблонен в горния пример, посочваме параметъра
на типа T, използвайки ъгловите скоби <T>. След това използваме този тип като тип
данни за параметрите на метода, както е показано на изображението по-долу.

В този момент, ако искате да извикате горния метод AreEqual(),трябва да посочите


типа данни, върху които трябва да работи методът. Например, ако искате да
работите с целочислени стойности, тогава трябва да извикате метода AreEqual(),
като посочите int като тип данни, както е показано на изображението по-долу, като
използвате ъглови скоби.

Методът AreEqual()работи както следва:

[Дата]
4
Ако искате да работите със символни низове, методът AreEqual() се извиква както
следва:
bool IsEqual= ClsCalculator.AreEqual<string>(“ABC”, “ABC”);

4. Шаблонни класове
Нека създадем шаблонен клас с шаблонен конструктор, поле и свойство от
параметризиран тип и шаблонен метод, както е показано по-долу. Ще създадем
класа MyGenericClass с <T>. Ъгловите скоби (“<>”) показват, че класът
MyGenericClass е шаблонен клас и типът за този клас ще бъде дефиниран по-късно.

Когато създаваме екземпляр на шаблонния клас MyGenericClass, трябва да посочим


типа, който компилаторът ще присвои на T. В следващия пример използваме int като
тип данни:

Програма 4
using System;
namespace GenericsDemo
{
//MyGenericClass is a Generic Class
class MyGenericClass<T>
{
//Generic variable
//The data type is generic
private T genericMemberVariable;
//Generic Constructor
//Constructor accepts one parameter of Generic type
public MyGenericClass(T value)
{
genericMemberVariable = value;
}
//Generic Method
//Method accepts one Generic type Parameter
//Method return type also Generic
public T genericMethod(T genericParameter)
{
Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(),
genericParameter);
Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(),
genericMemberVariable);
return genericMemberVariable;
}
//Generic Property
//The data type is generic
public T genericProperty { get; set; }
}}

class Program
{
static void Main()
{
MyGenericClass<int> integerGenericClass = new MyGenericClass<int>(10);

int val = integerGenericClass.genericMethod(200);


Console.ReadKey();
}}

[Дата]
5
Изход:

Следващата диаграма показва как T ще бъде заменен с типа данни int от


компилатора.

[Дата]
6
Компилаторът ще компилира горния клас, както е показано на фигурата по-
долу:

При създаване на обект можем да използваме всеки тип според нашето изискване.
Ако искаме да използваме низов тип, тогава трябва да създадем обект, както е
показано по-долу.
Програма 5
using System;

namespace GenericsForStrings
{
class MyGenericClass<T>
{

private T genericMemberVariable;
public MyGenericClass(T value)
{
genericMemberVariable = value;
}

public T genericMethod(T genericParameter)


{
Console.WriteLine("Parameter type: {0}, value: {1}",
typeof(T).ToString(), genericParameter);
Console.WriteLine("Return type: {0}, value: {1}",
typeof(T).ToString(), genericMemberVariable);
return genericMemberVariable;
}

public T genericProperty { get; set; }


}

[Дата]
7
class Program
{
static void Main(string[] args)
{
MyGenericClass < string >stringGenericClass= new
MyGenericClass<string>("Hello Generic World!");
stringGenericClass.genericProperty = "This is generic property example.";

string result = stringGenericClass.genericMethod("Generic Parameter");

Console.ReadKey();
}
}
}

Изход:
Parameter type: System.String, value: Generic Parameter
Return type: System.String, value: Hello Generic World!

[Дата]
8

You might also like