Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Заочники_АСОИ / Лекции / 02 Массивы и кортежи / Массивы, кортежи, перечисления.docx
Скачиваний:
27
Добавлен:
29.02.2016
Размер:
110.14 Кб
Скачать

Кортежи

Массивы комбинируют объекты одного типа, а кортежи (tuple) могут комбинировать объекты различных типов. Понятие кортежей происходит из языков функционального программирования, таких как F#, где они часто используются. С появлением .NET 4 корте­жи стали доступны в .NET Framework для всех языков .NET.

В .NET 4 определены восемь обобщенных классов Tuple и один статический класс Tuple, который служит фабрикой кортежей. Существуют различные обобщенные классы Tuple для поддержки различного количества элементов; например, Tuple<T1> содержит один элемент, Tuple<T1,Т2>  два элемента и т.д.

Метод Divide() демонстрирует возврат кортежа с двумя членами  Tuple<int,int>. Параметры обобщенного класса определяют типы членов, которые в данном случае оба це­лочисленные. Кортеж создан статическим методом Create() статического класса Tuple. Обобщенные параметры метода Create() определяют тип создаваемого экземпляра кор­тежа. Вновь созданный кортеж инициализируется переменными result и reminder для возврата результата деления:

public static Tuple<int,int> Divide (int dividend, int divisor)

{

int result = dividend/divisor;

int reminder = dividend%divisor;

return Tuple.Create<int, int>(result, reminder);

}

В следующем коде показан вызов метода Divide(). Элементы кортежа могут быть дос­тупны через свойства Item1 и Item2.

var result = Divide(5,2);

Console.WriteLine("результат деления: (0), остаток: {1}",

result.Item1, result.Item2);

В случае если имеется более восьми элементов, которые нужно включить в кортеж, можно использовать определение класса Tuple с восемью параметрами. Последний пара­метр называется TRest, в котором должен передаваться сам кортеж. Таким образом, есть возможность создавать кортежи с любым количеством параметров.

Для демонстрации этой функциональности напишем следующий код:

public class Tuple<T1, Т2, Т3, Т4, Т5, Т6, Т7, TRest>

Здесь последний параметр шаблона  сам тип кортежа, так что можно создать кортеж с любым числом элементов:

var tuple = Tuple.Create<string,string,string,int,int,int,double,

Tuple<int,int> ("Stephanie", "Alina", "Nagel", 2009, 6, 2, 1.37,

Tuple.Create<int,int>(52, 3490));

Структурное сравнение

Как массивы, так и кортежи реализуют интерфейс IStructuralEquatable и IStructuralComparable. Эти интерфейсы появились в .NET 4 и позволяют сравнивать не только ссылки, но и содержимое. Интерфейс реализован явно, поэтому при его использо­вании необходимо выполнять приведения массивов и кортежей. IStructuralEquatable служит для определения того, имеют ли два кортежа или массива одинаковое содержимое, a IStructuralComparable применяется для сортировки кортежей и массивов.

В следующем примере, демонстрирующем использование IStructuralEquatable, создан класс Person, который реализует интерфейс IEquatable. Этот интерфейс опреде­ляет строго типизированный метод Equals(), в котором сравниваются значения свойств FirstName и LastName:

public class Person: IEquatable<Person>

{

public int Id {get; private set; }

public string FirstName {get; set;}

public string LastName {get; set;}

public override string ToString()

{

return String.Format("{0}, {1} {2}", Id, FirstName, LastName);

}

public override bool Equals(object obj)

{

if(obj == null) throw new ArgumentNullException("obj");

return Equals(obj as Person);

}

public override int GetHashCode()

{

return Id.GetHashCode();

}

public bool Equals(Person other)

{

if (other == null) throw new ArgumentNullException("other");

return this.Id==other.Id && this.FirstName==other.FirstName &&

this.LastName == other.LastName;

}

}

Ниже создаются два массива элементов Person. Оба они содержат один и тот же объ­ект Person с переменной по имени janet и два разных объекта Person с одинаковым со­держимым. Операция сравнения != возвращает true, потому что на самом деле это два разных массива, на которые ссылаются две переменные по имени persons1 и persons2. Поскольку метод Equals() с одним параметром не переопределяется классом Array, то же самое случается и с операцией == при сравнении ссылок  они не совпадают.

var janet = new Person {FirstName = "Janet”, LastName = "Jackson"};

Person [] persons1 = { new Person

{

FirstName = "Michael",

LastName = "Jackson"

},

janet

};

Person[] persons2 = { new Person

{

FirstName = "Michael",

LastName = "Jackson"

},

janet

};

if (persons1 != persons2)

Console.WriteLine("разные ссылки");

Вызывая метод Equals(), определенный в IStructuralEquatable как принимаю­щий первый параметр типа object и второй типа IEqualityComparer, можно опре­делить, как именно должно выполняться сравнение, передавая объект, реализующий IEqualityComparer<T>. Реализация IEqualityComparer по умолчанию предоставля­ется классом EqualityComparer<T>. В ней производится проверка, реализует ли тип интерфейс IEquatable, и вызывается IEquatable.Equals(). Если тип не реализует IEquatable, то для выполнения сравнения вызывается метод Equals() базового класса Object.

Класс Person реализует IEquatable<Person>, где содержимое объектов сравнивается, и оказывается, что массивы действительно включают одинаковое содержимое:

if ((persons1 as IStructuralEquatable).Equals(persons2,

EqualityComparer<Person>.Default))

{

Console.WriteLine("одинаковое содержимое");

}

Теперь будет показано, как то же самое можно сделать с применением кортежей. Ниже создаются два экземпляра кортежей с одинаковым содержимым. Разумеется, поскольку ссыл­ки t1 и t2 указывают на два разный объекта, операция сравнения != возвращает true:

var t1 = Tuple.Create<int, string>(l, "Stephanie");

var t2 = Tuple.Create<int, string>(l, "Stephanie");

if (t1 != t2) Console.WriteLine("не одинаковое содержимое");

Класс Tuple<> предоставляет два метода Equals(): один, переопределяющий реа­лизацию базового класса Object, с object в качестве параметра, а второй опреде­лен интерфейсом IStructuralEqualityComparer, с двумя параметрами  object и IEqualityComparer. Как показано, другой кортеж может быть передан в первый метод. Чтобы получить ObjectEqualityComparer<object> для сравнения, этот метод использу­ет EqualityComparer<object>.Default. Таким образом, каждый элемент в кортеже срав­нивается за счет вызова метода Object.Equals(). Если для каждого элемента возвращает­ся true, конечным результатом метода Equals() также будет true, что мы и видим здесь с одинаковыми значениями int и string: