dotSITE
Вопросы/Ответы Учебник по ASP.NET Форумы
новости материалы решения форумы группы настройки/о проекте

Классы

Примачание: данное описание не претендует на полноту и будет в дальнейшем дополнено

Одним из основных понятий ООП является класс. Соответственно, это понятие занимает центральное место и в идеологии C#. Описывать понятие класса здесь явно не место - мы предполагаем, что читатель уже знаком с каким-либо объектно-ориентированным языком. Возможно мы дополним наш учебник ликбезом по ООП в дальнейшем.

Здесь же мы лишь опишем класс как структуру данных, содержащую члены-данные (такие как константы и поля), функциональные члены (методы, свойства, события, индексаторы, операторы, конструкторы и деструкторы) и вложенные типы. Классы также поддерживают наследование.

Простейшее объявление класса выглядит так:

// Класс объявленный как public, доступен отовсюду, включая другие сборки
// Можно также написать internal - класс будет доступен только из текущей сборки
public class HelloWorldClass
{
    public void HelloWorld()
    {
        Console.WriteLine("Hello, world");
    }
}

Можно также сделать класс абстрактным:

public abstract class AgentFactory
{
    public void WriteInfo()
    {
        Console.WriteLine("I'm agent factory");
    }

    public abstract Agent CreateAgent();
}

Такие классы могут содержать абстрактные методы (методы, которые не реализованы в текущем классе, но должны быть реализованы в неабстрактных потомках). Фбстрактные классы не могут быть инстанцированы. То есть для использования этого класса, должен быть написан потомок:

public class FootballAgentFactory : AgentFactory
{
    public Agent CreateAgent()
    {
        return new FootballAgent();
    }
}

Если же вы наоборот не хотите, чтобы от вашего класса кто-то наследовался, объявите его как sealed:

public sealed class IAmTheCoolest
{
    public void WhoAmI()
    {
        Console.WriteLine("I am cool and I don't want any inheritance");
    }
}

// Это приведет к ошибке компиляции
public class IAmMoreCoolThanTheCoolest : IAmTheCoolest
{
    public void IAmTheCoolest()
    {
        Console.WriteLine("I'm even cooler that the coolest");
    }
}

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

public class Base1
{
}

public class Base2
{
}

public interface Interface1
{
}

public interface Interface2
{
}

// Попытка наследования нескольких классов приведет к ошибке
public class MyClass : Base1, Base2
{
}

// Зато можно реализовывать несколько интерфейсов
public class MyClass2 : Base1, Interface1, Interface2
{
}

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

В теле класса объявляются его члены. Далее мы опишем все виды членов класса.

Поля

Поле представляет переменную, связанную с данным классом или его экземпляром.

public class MyClass
{
    // Указывается что это поле доступно из любого класса, даже из другой сборки
    // Также можно указать protected - поле будет доступно только из классов-наследников    
    // и private - доступно только из текущего класса.
    public int a;

    // Присваиваем начальное значение в конструкторе
    public MyClass()
    {
        a = 3;
    }
}        

public class Application
{
    public static void Main()
    {
        MyClass myClass = new MyClass();

        // a = 5
        Console.WriteLine("a = {0}", myClass.a);

        myClass.a += 5;

        // a = 10
        Console.WriteLine("a = {0}", myClass.a);
    }           
}

Также можно обявить поле как readonly - запрещается запись в поле, кроме как при инициалищации посредством инийиализатора или конструктора.

public class MyClass
{
    // Присваиваем начальное значение в инициализаторе
    readonly int a = 1;

    // Присваиваем начальное значение в конструкторе
    public MyClass()
    {
        a = 3;
    }

    public MyMethod()
    {
        a = 5; // Ошибка компиляции
    }
}        

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

Модификатор static декларирует принадлежность члена класса всему классу, а не конкретному члену. Доступ к таким членам осуществляется через имя класса, а не его экземпляра.

public class MyStaticMemberClass
{
    public static int a = 10;

    public MyMethod()
    {
        a = 5; 
    }
}        

public class Application
{
    public static void Main()
    {
        // a = 10
        Console.WriteLine("a = {0}", MyStaticMemberClass.a);

        MyStaticMemberClass.a = 2;

        // a = 2
        Console.WriteLine("a = {0}", MyStaticMemberClass.a);
    }
}

Методы

Методы представляют собой действия, которые можно произвести в связи с данным классом.

public class MyHelper
{
    private int a, b;

    public MyHelper( int a, int b )
    {
        this.a = a;
        this.b = b;
    }

    public int Max()
    {
        return a > b ? a : b;
    }
}

public class Application
{
    public static void Main()
    {
        MyHelper helper = new Helper(2, 10);

        // MAX(2, 10) = 10
        Console.WriteLine("MAX(2, 10) = {0}", helper.Max());
    }
}

Возможные модификаторы - уже описанные public, static, protected, abstract и еще virtual, override, new и extern.

Методам также можно передавать параметры, которые параметризуют его действия.

Формат списка параметров такой:
модификатор параметра тип параметра имя параметра

Единственной необычной частью является модификатор параметра. Существуют следующие модификаторы параметров:

Также существует возможность декларировать метод как принимающий произвольное число аргументов. Для этого используется следующий синтаксис:

        param тип элемента[] имя списка
        

Для пояснения приведем пример:

class Application
{
    static void SampleMethod( string text, params string[] args )
    {           
        Console.WriteLine(text);

        foreach (string s in args)
        {
            Console.WriteLine(s);
        }
    }

    public static void Main()
    {
        SampleMethod("Parameters list:", "Param1", "Param2", "Param3");
    }
}
        

Свойства

Свойства расширяют возможности полей. Они представляют собой типизированные объекты, у которых можно получить значение и (опционально) записать в них новое значение. При выполнении этих действий выполняется определяемый программистом код. Синтаксис определения полей следующий:

    модификаторы тип имя
    {
        get Тело get
        get Тело set
    }
    

В теле get пишется код, который выполняется при получении значения свойства. В теле set пишется код, который выполняется при установке нового значения. При этом в set доступно присваеваемое значение через ключевое слово value:

public class SampleClass
{
    private static int a;

    public static int A
    {
        get
        {
            return a;
        }
        set
        {
            a = value;
        }
    }

    public static void Main()
    {
        A = 2;

        Console.WriteLine("A = {0}", A);
    }
}
    

Этот пример демонстрирует распространенный прием инкапсуляции полей.

Индексаторы

Одним из важных направлений развития языков программирования является удобство и наглядность кода. Именно стремление упростить структуру кода привело в свое время к перегрузке операторов С++ и свойствам в Object Pascal. Предлагая новый язык специально для своей новой платформы, Microsoft, разумеется, не могла не учесть это сторону вопроса. Поэтому язык включает в себя свойства (properties) и индексаторы (indexers).

При написании приложений часто возникает необходимость создавать объекты, представляющие коллекцию других объектов (они не обязательно явно хранят в себе все эти объекты, но предоставляют доступ к ним). В языках вроде C или Java для этого использовались специальные функции (методы) вроде GetItem( int index ). Конечно, это возможный подход, но часто, когда нужно часто обращаться к элементам коллекции, неудобно каждый раз писать громоздкие конструкции.

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

Для того, чтобы объявить в классе индексатор, нужно использовать следующий синтаксис:

        тип this [список_параметров]
    

Где тип - тип возвращаемого значения (тип элемента коллекции), а список параметров - типы и имена параметров, используемых для идентификации элемента коллекции.

Индексатор может иметь любые модификаторы, кроме static, а к параметрам нельзя применять модификаторы out и ref.

Для определения кода индексатора, нужно прописать ему метода доступа - get и, возможно, set (если индексатор у вас позволяет менять элементы). При этом в методе get доступны все параметры индексатора как переменные, а в методе set дополнительно к ним параметр value, представляющий новое значение элемента. Таким образом, индексатор примет вид, аналогичный следующему:

public object this [int index]
{
    get
    {
        return GetItem(index);
    }
    set
    {
        SetItem(index, value);
    }
}
    

Для полной ясности картины, приведем небольшой пример:

using System;


public CustomIndexerClass
{
    // Объявляем внутренний массив, где будут храниться действительные значения
    private int internalArray = new int[10];

    // Объявляем индексатор
    public int this [int index]
    {
        // Доступ на чтение
        get
        {

            // Проверка границ
            if (index < internalArray.GetLowerBound(0) || index > internalArray.GetUpperBound(0))
                return 0;

            // Врщвращаем значение соответствующего элемента массива
            return internalArray[index];
        }
        set
        {
            // Проверка границ и запись нового значения
            if (index >= internalArray.GetLowerBound(0) && index <= internalArray.GetUpperBound(0))
                internalArray[index] = value;
        }
    }

    public class ApplicationClass
    {
        public static void Main()
        {
            CustomIndexerClass myIndexer = new CustomIndexerClass();

            myIndexer[1] = 10;
            myIndexer[5] = 7;

            for (int i = 0; i < 10; i++)
                Console.WriteLine("myIndexer[{0}] = {1}\n", i, myIndexer[i]);
        }
    }
}        
    

Эта программа создает класс, имеющий индексатор, который просто читает или записывает значения во внутреннем массиве. Главная программа сначала изменяет несколько ячеек массива, пользуясь индексатором, а затем читает все его ячейки последовательно.

Констукторы

Деструкторы

Деструктор - это метод, который вызывается при уничтожении объекта. Так как в .NET CLR используется сборщик мусора, нельзя явно удалить определенный экземпляр. Удаление происходит когда никакой код уже не может воспользоваться этим экземпляром. Деструкторы определяются как методы с именем, совпадающим с именем класса, предваренным знаком ~ (тильда):
public class A
{
    ~A
    {
        Console.WriteLine("I'm being descructed");
    }
}

public class Application
{
    public static void Main()
    {
        A a = new A();
        a = null;
    }
} 
        

Программа выведет "I'm being destructed"

<< Предыдущая Следующая >>

Контакт Реклама на сайте Спонсорам Веб мастерам

Лицензионное соглашение - © 2000-2012 dotSITE
Хостинг .NET предоставлен PARKING.RU
Поддержку сайта осуществляет Murano Software Inc., Offshore software development