Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Yap_otvety_na_24-30.docx
Скачиваний:
4
Добавлен:
01.05.2025
Размер:
334 Кб
Скачать
☆

25)Абстрактный класс object.Метод ToString() .

  • Определенный в C# класс object является базовым для всех без исключения типов (классов и обычных типов).

  • Если при создании класса не указан наследуемый класс, то таковым по умолчанию считается класс object.

è ссылочная переменная типа object может ссылаться на объект любого типа,

  • Полная форма имени класса - System.Object

  • Данный класс принадлежит библиотеке классов .NET Framework.

  • Многие методы этого класса эффективны для любых наследующих классов.

Методы класса

public virtual string ToString ( )

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

  • При переопределении можно возвратить любую строку.

  • Метод часто используют для получения информации о состоянии объекта. Например:

public override string ToString ( )

{

return “это экземпляр класса MyClass”;

using System;

namespace MyTest

{

public class Class1: Object

{

}

public class Class2: Class1

{

}

public class Test

{

public static void Main()

{

Class1 obj1 = new Class1();

Class2 obj2 = new Class2();

object obj = obj2;

Class1 b = obj2;

Console.WriteLine("obj1: Type - {0}", obj1.GetType());

Console.WriteLine("obj2: Type - {0}", obj2.GetType());

Console.WriteLine("object obj = obj2: Type - {0}", obj.GetType());

Console.WriteLine("Class1 b = obj2: Type - {0}", b.GetType());

}

}

}

типы указываются в полной форме, с пространством имен.

Переопределение виртуальных методов в обобщенном классе

В обобщенном классе виртуальный метод может быть переопределен таким же образом, как и любой другой метод. В качестве примера рассмотрим следующую программу, в которой переопределяется виртуальны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();

}

}

}

26)Интерфейсы

C# --- Руководство по C# --- Интерфейсы

Для начала ознакомимся с формальным определением типа интерфейса. Интерфейс (interface) представляет собой не более чем просто именованный набор абстрактных членов. Абстрактные методы являются чистым протоколом, поскольку не имеют никакой стандартной реализации. Конкретные члены, определяемые интерфейсом, зависят от того, какое поведение моделируется с его помощью. Это действительно так. Интерфейс выражает поведение, которое данный класс или структура может избрать для поддержки. Более того, каждый класс (или структура) может поддерживать столько интерфейсов, сколько необходимо, и, следовательно, тем самым поддерживать множество поведений.

Нетрудно догадаться, что в библиотеках базовых классов .NET поставляются сотни предопределенных типов интерфейсов, которые реализуются в различных классах и структурах. Например, в состав ADO.NET входит множество поставщиков данных, которые позволяют взаимодействовать с определенной системой управления базами данных. Это означает, что в ADO.NET на выбор доступно множество объектов соединения (SqlConnection, OracleConnection, OdbcConnection и т.д.).

В интерфейсе ни у одного из методов не должно быть тела. Это означает, что в интерфейсе вообще не предоставляется никакой реализации. В нем указывается только, что именно следует делать, но не как это делать. Как только интерфейс будет определен, он может быть реализован в любом количестве классов. Кроме того, в одном классе может быть реализовано любое количество интерфейсов.

Для реализации интерфейса в классе должны быть предоставлены тела (т.е. конкретные реализации) методов, описанных в этом интерфейсе. Каждому классу предоставляется полная свобода для определения деталей своей собственной реализации интерфейса. Следовательно, один и тот же интерфейс может быть реализован в двух классах по-разному. Тем не менее в каждом из них должен поддерживаться один и тот же набор методов данного интерфейса. А в том коде, где известен такой интерфейс, могут использоваться объекты любого из этих двух классов, поскольку интерфейс для всех этих объектов остается одинаковым. Благодаря поддержке интерфейсов в С# может быть в полной мере реализован главный принцип полиморфизма: один интерфейс — множество методов.

Интерфейсы объявляются с помощью ключевого слова interface. Ниже приведена упрощенная форма объявления интерфейса:

interface имя{

возвращаемый_тип имя_метода1 (список_параметров);

возвращаемый_тип имя_метода2 (список_параметров);

// ...

возвращаемый_тип имя_методаЫ(список_параметров);

}

где имя — это конкретное имя интерфейса. В объявлении методов интерфейса используются только их возвращаемый_тип и сигнатура. Они, по существу, являются абстрактными методами. Как пояснялось выше, в интерфейсе не может быть никакой реализации. Поэтому все методы интерфейса должны быть реализованы в каждом классе, включающем в себя этот интерфейс. В самом же интерфейсе методы неявно считаются открытыми, поэтому доступ к ним не нужно указывать явно.

Помимо методов, в интерфейсах можно также указывать свойства, индексаторы и события. Интерфейсы не могут содержать члены данных. В них нельзя также определить конструкторы, деструкторы или операторные методы. Кроме того, ни один из членов интерфейса не может быть объявлен как static.

Как только интерфейс будет определен, он может быть реализован в одном или нескольких классах. Для реализации интерфейса достаточно указать его имя после имени класса, аналогично базовому классу. Ниже приведена общая форма реализации интерфейса в классе:

class имя_класса : имя_интерфейса {

// тело класса

}

где имя_интерфейса — это конкретное имя реализуемого интерфейса. Если уж интерфейс реализуется в классе, то это должно быть сделано полностью. В частности, реализовать интерфейс выборочно и только по частям нельзя.

В классе допускается реализовывать несколько интерфейсов. В этом случае все реализуемые в классе интерфейсы указываются списком через запятую. В классе можно наследовать базовый класс и в тоже время реализовать один или более интерфейс. В таком случае имя базового класса должно быть указано перед списком интерфейсов, разделяемых запятой.

Методы, реализующие интерфейс, должны быть объявлены как public. Дело в том, что в самом интерфейсе эти методы неявно подразумеваются как открытые, поэтому их реализация также должна быть открытой. Кроме того, возвращаемый тип и сигнатура реализуемого метода должны точно соответствовать возвращаемому типу и сигнатуре, указанным в определении интерфейса.

Давайте рассмотрим пример:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace ConsoleApplication1

{

// Создаем два интерфейса, описывающих абстрактные методы

// арифметических операций и операций Sqrt и Sqr

public interface IArOperation

{

// Определяем набор абстрактных методов

int Sum();

int Otr();

int Prz();

int Del();

}

public interface ISqrSqrt

{

int Sqr(int x);

int Sqrt(int x);

}

// Данный класс реализует интерфейс IArOperation

class A : IArOperation

{

int My_x, My_y;

public int x

{

set { My_x = value; }

get { return My_x; }

}

public int y

{

set { My_y = value; }

get { return My_y; }

}

public A() { }

public A(int x, int y)

{

this.x = x;

this.y = y;

}

// Реализуем методы интерфейса

public virtual int Sum()

{

return x + y;

}

public int Otr()

{

return x - y;

}

public int Prz()

{

return x * y;

}

public int Del()

{

return x / y;

}

// В данном классе так же можно реализовать собственные методы

public virtual void rewrite()

{

Console.WriteLine("Переменная x: {0}\nПеременная y: {1}",x,y);

}

}

// Данный класс унаследован от класса А, но при этом в нем не нужно

// заново реализовывать интерфейс, но при этом можно переопределить

// некоторые его методы

class Aa : A

{

public int z;

public Aa(int z, int x, int y)

: base(x, y)

{

this.z = z;

}

// Переопределим метод Sum

public override int Sum()

{

return base.x + base.y + z;

}

public override void rewrite()

{

base.rewrite();

Console.WriteLine("Переменная z: " + z);

}

}

// Данный класс унаследован от класса А, и при этом

// реализует интерфейс ISqrSqrt

class Ab : A, ISqrSqrt

{

public int Sqr(int x)

{

return x * x;

}

public int Sqrt(int x)

{

return (int)Math.Sqrt((double)(x));

}

}

class Program

{

static void Main()

{

A obj1 = new A(x: 10, y: 12);

Console.WriteLine("obj1: ");

obj1.rewrite();

Console.WriteLine("{0} + {1} = {2}",obj1.x,obj1.y,obj1.Sum());

Console.WriteLine("{0} * {1} = {2}", obj1.x, obj1.y, obj1.Prz());

Aa obj2 = new Aa(z: -3, x: 10, y: 14);

Console.WriteLine("\nobj2: ");

obj2.rewrite();

Console.WriteLine("{0} + {1} + {3} = {2}", obj2.x, obj2.y, obj2.Sum(), obj2.z);

Console.ReadLine();

}

}

}

Обратите внимание на структуру реализации данных интерфейсов в приведенном примере. Диаграмма классов, иллюстрирующая вышеуказанный пример показана ниже:

Явная реализация интерфейса

C# --- Руководство по C# --- Явная реализация интерфейса

Единственный класс или структура может реализовать любое количество интерфейсов. Из-за этого всегда существует вероятность реализации интерфейсов с членами, имеющими идентичные имена, и, следовательно, возникает необходимость в устранении конфликтов на уровне имен. При реализации члена интерфейса имеется возможность указать его имя полностью вместе с именем самого интерфейса. В этом случае получается явная реализация члена интерфейса, или просто явная реализация.

Когда один интерфейс наследует другой, то в производном интерфейсе может быть объявлен член, скрывающий член с аналогичным именем в базовом интерфейсе. Такое сокрытие имен происходит в том случае, если член в производном интерфейсе объявляется таким же образом, как и в базовом интерфейсе. Но если не указать в объявлении члена производного интерфейса ключевое слово new, то компилятор выдаст соответствующее предупреждающее сообщение.

Для явной реализации интерфейсного метода могут быть две причины. Во-первых, когда интерфейсный метод реализуется с указанием его полного имени, то такой метод оказывается доступным не посредством объектов класса, реализующего данный интерфейс, а по интерфейсной ссылке. Следовательно, явная реализация позволяет реализовать интерфейсный метод таким образом, чтобы он не стал открытым членом класса, предоставляющего его реализацию. И во-вторых, в одном классе могут быть реализованы два интерфейса с методами, объявленными с одинаковыми именами и сигнатурами. Но неоднозначность в данном случае устраняется благодаря указанию в именах этих методов их соответствующих интерфейсов. Рассмотрим каждую из этих двух возможностей явной реализации на следующем примере:

using System;

namespace ConsoleApplication1

{

public interface IName

{

void WriteName();

}

public interface INameFamily

{

// Объявляем в данном интерфейсе такой же метод

void WriteName();

void WriteFamily();

}

public interface IUserInfo : INameFamily

{

// Обязательно нужно указать ключевое слово new

// чтобы не скрывались методы базового интерфейса

new void WriteName();

void WriteUserInfo();

}

// Класс, реализующий два интерфейса

class UserInfo : IUserInfo,IName

{

string ShortName, Family, Name;

public UserInfo(string Name, string Family, string ShortName)

{

this.Name = Name;

this.Family = Family;

this.ShortName = ShortName;

}

// Используем явную реализацию интерфейсов

// для исключения неоднозначности

void IName.WriteName()

{

Console.WriteLine("Короткое имя: " + ShortName);

}

void INameFamily.WriteFamily()

{

Console.WriteLine("Фамилия: " + Family);

}

void INameFamily.WriteName()

{

Console.WriteLine("Полное имя: " + Name);

}

void IUserInfo.WriteName() { }

public void WriteUserInfo()

{

UserInfo obj = new UserInfo(Name, Family, ShortName);

// Для использования закрытых методов необходимо

// создать интерфейсную ссылку

IName link1 = (IName)obj;

link1.WriteName();

INameFamily link2 = (INameFamily)obj;

link2.WriteName();

link2.WriteFamily();

IUserInfo link3 = (IUserInfo)obj;

link3.WriteName();

}

}

class Program

{

static void Main()

{

UserInfo obj = new UserInfo(Name: "Alexandr", ShortName: "Alex", Family: "Erohin");

obj.WriteUserInfo();

Console.ReadLine();

}

}

}

Важно уяснить, что интерфейсы являются фундаментальным компонентом .NET Framework. Какого бы типа приложение не разрабатывалось (веб-приложение, приложение с настольным графическим интерфейсом, библиотека доступа к данными и т.п.), работа с интерфейсами будет обязательной частью этого процесса. Подводя итог всему изложенному, отметим, что интерфейсы могут приносить чрезвычайную пользу в следующих случаях:

  • При наличии единой иерархии, в которой только какой-то набор производных типов поддерживает общее поведение.

  • При необходимости моделировать общее поведение, которое должно встречаться в нескольких иерархиях, не имеющих общего родительского класса помимо System.Object.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]