Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > константные функции в C#


Автор: Alek86 3.10.2007, 16:03
есть ли возможность в C# объявить аналог константной функции C++?
чтобы, вызывая ее, я был уверен, что она не поменяет переменные-члены своего класса

Автор: mr.DUDA 3.10.2007, 16:06
ИМХО, нет такого.

Автор: iad 4.10.2007, 08:48
Только так:
Код

    public class ConstantClass//класс методы которого не могут менять содержимое объекта
    {
        protected string _field;
        
        public string GetField()//const method
        {
            return _field;
        }

    }

    public class CanModifiedClass:ConstantClass//класс методы которого изменить содержимое могут
    {
        public void SetField(string f)
        {
            _field = f;
        }
    }

    public class Container
    {
        CanModifiedClass _cls = new CanModifiedClass();
        
        public ConstantClass cls//константная ссылка аля C++
        {
            get
            {
                return (ConstantClass)_cls;
            }
        }

        protected void ChangeCls()
        {
            _cls.SetField("lalala");
        }
    }

еще можно использовать модификаторы доступа internal, но это уже будет нарушением инкапсуляции

Автор: tol05 4.10.2007, 10:35
iad, это отдаленно напоминает реализацию свойств...

Alek86, ИМХО имеет в виду обычные плюсовые константные ф-ции. 
Если сделать свойства только на чтение и работать только через них (а это правильно, в принципе), то значения членов класса изменить будет нельзя.

Опять же, Alek86, смотря что понимать под изменением члена класса (и какой тип члена класса). Если
Код

class A
{
   private int m_i=5;

   public int GetIncrementedI()
  {
      return InternalIncrement(m_i);
  } 

   private int InternalIncrement(int value)
  {
      return ++value;
  } 
}

то m_i не изменится. Но если член класса - ссылочный, то он изменится.
Методы класса имеют неограниченный доступ к членам своего класса. Повторяю - не работай с полями класса напрямую нигде, кроме как в конструкторах, инициализаторах и свойствах.

Автор: VisualProgrammerNET 4.10.2007, 11:30
Цитата(iad @  4.10.2007,  08:48 Найти цитируемый пост)
еще можно использовать модификаторы доступа internal, но это уже будет нарушением инкапсуляции 

Немного я конечно не в тему... Ну почему? Почему internal - нарушение инкапсуляции? Извне сборки интернал-поля же не видны, правильно? Дык в чём проблема? Тем более порой бывает гораздо проще тупо объявить переменную интерналом, чем перелопачивать всю иерархию классов...

Да и вообще, с рефлектором не то, что internal, private поля - как на ладони...  smile 

Автор: Alek86 4.10.2007, 12:01
спасибо за ответы, но самый хороший ответ прозвучал у mr.DUDA smile

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

слово const в сях давало хоть какую-то гарантию... 

и, не подскажет ли кто, почему эту возможность в шарпе убрали?

Автор: iad 4.10.2007, 15:27
Цитата(tol05 @  4.10.2007,  11:35 Найти цитируемый пост)
Alek86, ИМХО имеет в виду обычные плюсовые константные ф-ции
 я тоже их имею ввиду

Цитата(tol05 @  4.10.2007,  11:35 Найти цитируемый пост)
Если сделать свойства только на чтение и работать только через них (а это правильно, в принципе), то значения членов класса изменить будет нельзя.
Неужели?
Код

    class a
    {
        int[] _member;
        public a()
        {
            _member = new int[2];
            _member[0] = 0;
            _member[1] = 1;
        }
        public int[] Member
        {
            get
            {
                return _member;
            }
        }
    }
    class tester
    {
        a a = new a();
        void test()
        {
            a.Member[0] = 100;
        }
    
}




Автор: tol05 4.10.2007, 15:34
iad

В том контексте, в котором я говорил (и с тем примером, что я привел) - я не сказал направды
Описывать все варианты, все типы данных (а потом и отличия между ними и т.д. и т.п. ) ....

Мне что, переписать себе в пост несколько толстых учебников???

Короче... даже отвечать тебе - "не сто'ит" ....

:(((

Автор: iad 4.10.2007, 17:52
Цитата(tol05 @  4.10.2007,  16:34 Найти цитируемый пост)
я не сказал направды
ты сказал правду, ты подписался в некомпетентности и поэтому ты абсолютно прав: "отвечать мне не стоит"

Автор: ivashkanet 4.10.2007, 18:39
iad, пожалуйста без наездов! Тут идёт обсуждение! А не мерянье пип.

Тем более, что tol05, ИМХО, прав: хочешь запретить изменение элементов класса --- убери все сеттеры. 
Твой пример ни на что не годиться, так как программер, кот запретит изменение члена класса позаботиться, чтобы и этот член не имел интерфейса для прямого своего изменения.

А создавать такие классы как у тебя, а потом говорить, что я запретил изменять их элементы как минимум смешно.


Автор: iad 4.10.2007, 18:55
Цитата(ivashkanet @  4.10.2007,  19:39 Найти цитируемый пост)
Твой пример ни на что не годиться, так как программер, кот запретит изменение члена класса позаботиться, чтобы и этот член не имел интерфейса для прямого своего изменения.
так вот программер позаботится по аналогии с моим первым примером(жаль, что невнимательно чиаешь данное обсуждение)а в С++ есть возможность без гимора решить задачу.. C# таких возможностей не дает - поэтому пытаемся скандалить smile . Если где-то я не прав - поставьте на путь истинный smile 

Автор: ivashkanet 4.10.2007, 19:00
iad, у тя пример, всего лишь пример (хотя я такого бы не писал)... Я же описал общий подход.

Кста, для САБЖА может применяться паттерн декоратор. 
Посмотреть на его реализацию можно в самом фрэймворке. 
Класс ArrayList и статический метод ReadOnly:

Код

public static ArrayList ReadOnly(ArrayList list)
{
    if (list == null)
    {
        throw new ArgumentNullException("list");
    }
    return new ReadOnlyArrayList(list);
}


Вот сам Класс декоратор:
Код

[Serializable]
private class ReadOnlyArrayList : ArrayList
{
    // Fields
    private ArrayList _list;

    // Methods
    internal ReadOnlyArrayList(ArrayList l)
    {
        this._list = l;
    }

    public override int Add(object obj)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection"));
    }

    public override void AddRange(ICollection c)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection"));
    }

    public override int BinarySearch(int index, int count, object value, IComparer comparer)
    {
        return this._list.BinarySearch(index, count, value, comparer);
    }

    public override void Clear()
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection"));
    }

    public override object Clone()
    {
        ArrayList.ReadOnlyArrayList list = new ArrayList.ReadOnlyArrayList(this._list);
        list._list = (ArrayList) this._list.Clone();
        return list;
    }

    public override bool Contains(object obj)
    {
        return this._list.Contains(obj);
    }

    public override void CopyTo(Array array, int index)
    {
        this._list.CopyTo(array, index);
    }


 // .... и так далее



Автор: iad 4.10.2007, 19:08
Декоратор тоже вариант. ок.  Но проверка изменения объекта будет в рантайме. си++ый вариант позволяет отследить попытки изменения на этапе компиляции.. считаю это большим плюсом и с удовольствием бы пользовался такой возможностью smile 

Автор: tol05 5.10.2007, 10:23
Цитата(iad @  4.10.2007,  17:52 Найти цитируемый пост)
ты сказал правду, ты подписался в некомпетентности и поэтому ты абсолютно прав: "отвечать мне не стоит"


два момента:
1. Где я был некомпетентен? В какой строчке какого поста? Я не начал объяснять что есть ссылочные типы, есть типы значений и т.д. и т.п.? Не просили
2. Какова вообще была твоя цель, когда ты свой первый пост писал? Автору помочь или себя показать? Автору ты не помог и даже не пытался. Ну а себя... да, показал.

-1

Автор: ivashkanet 5.10.2007, 10:35
Цитата(iad @  4.10.2007,  19:08 Найти цитируемый пост)
си++ый вариант позволяет отследить попытки изменения на этапе компиляции.. считаю это большим плюсом и с удовольствием бы пользовался такой возможностью

Кто нить мне может объяснить нафик этот const нужен?

Я понимаю еще такую конструкцию:
Код
doSomething(const value);


Но какой толк от конструкции:
Код
void doSomething(const int value) {/*...*/}

Ведь ты САМ пишешь эту функцию и ты САМ знаешь что можно менять, а что нет. 
Зачем ещё просить компилятор: "Вот это вот менять ни в коем случае нельзя! Так что напомни, мне глупому, если я захочу это поменять..."

Автор: iad 5.10.2007, 11:20
Цитата(ivashkanet @  5.10.2007,  11:35 Найти цитируемый пост)
Но какой толк от конструкции:код C#1:void doSomething(const int value) {/*...*/}
конечно нет толку, тем более для int. смысл есть в конструкции
Код

 public string ConstantFunction()const// - указание компилятору что эта функция не меняет состояние объекта
        {}
только она нереальна в C#. Смысл в том что я не хочу, при определенных условиях, давать возможность пользователям моего класса изменять содержимое объекта. 
Цитата(ivashkanet @  5.10.2007,  11:35 Найти цитируемый пост)
Ведь ты САМ пишешь эту функцию....Так что напомни, мне глупому, если я захочу это поменять...
Не тебе. А пользователю твоего класса, потому что не всегда проекты пишутся в одно лицо. 

Автор: ivashkanet 5.10.2007, 11:33
Цитата(iad @  5.10.2007,  11:20 Найти цитируемый пост)
 public string ConstantFunction()const// - указание компилятору что эта функция не меняет состояние объекта

Подробнее, плиз. Т.е. я должен помечать все функции, кот не меняют значения переменных таким образом?

И что-то я не нашел такого здесь: http://en.wikipedia.org/wiki/Const_correctness

P.S. 
Цитата(iad @  5.10.2007,  11:20 Найти цитируемый пост)
тем более для int

int это был пример. не надо быть таким категоричным

Добавлено через 1 минуту и 14 секунд
Цитата(ivashkanet @  5.10.2007,  11:33 Найти цитируемый пост)
Т.е. я должен помечать все функции, кот не меняют значения переменных таким образом?

А если не пометил, то что? Ее нельзя использовать? Требую пояснений.
(Прошу отнестись с пониманием. Я в плюсах не силен. И с такой фичей не сталкивался).

Автор: iad 5.10.2007, 17:12
Цитата(ivashkanet @  5.10.2007,  12:33 Найти цитируемый пост)
Подробнее, плиз. Т.е. я должен помечать все функции, кот не меняют значения переменных таким образом?
ну да, типа того. Только не должен помечать, а можешь - если хочешь. это синтаксис C++, помеченная таким образом функция говорит компилятору что содержимое объекта не будет изменено. Допустим у тебя есть класс контейнер. В нем находится мембер типа Закголовок. Пусть это будет какая-нибудь коллекция, описывающая заголовок таблицы.  Причем эта коллекция - самодостаточный класс, который может использоваться для других целей, абсолютно самостоятельно. Поэтому мы не хотим его специально переписывать для класса контейнера. Есть еще в классе контейнере сама таблица в виде какого-нибудь двумерного массива. Логичиски этот массив и заголовок связаны друг с другом. Одна из размернстей таблицы и размерность заголовка должну быть одинаковы. Если по С#-пному я открою доступ (пусть даже через ридонли свойство) к заголовку, пользователь моего класса сможет сделать заголовку какой-нибудь Clear() или Resize() и размерности перестану совпадать, и пойдут рантайм ошибки. Конечно это будут ошибки проектировщика, надо было предусмотреть такую фигню, но.. Если мы предоставим доступ к заголовку как константную ссылку, то компилятор не даст дергать эту ссылку за методы Clear() или Resize(), мы же их не пометили как const... и другой разработчик, который использует твой контейнер, не сможет навредить ему при всем желании, даже не удосужившись прочитать описание. Экономия времени по любому, тк не надо изыскивать красивые архитектурные решения, для обеспечения 100%-й инкапсуляции или заморачиваться на документацию, при отказе от полной реализации этой самой инкапсуляции... Ну как мог рассказал smile

Добавлено через 9 минут и 3 секунды
в догонку
тогда появится смысл в конструкции 
Код

        void doSomething(const int value) {/*...*/}
 только опять же не int, а на основе вышесказанного что-то типа
Код

void doSomething(const container value_) {value_.Header.Clear();//error}


Автор: mr.DUDA 5.10.2007, 17:32
Кстати, если уж лезть в дебри, то гарантировать сохранность объектов в многопоточном приложении никто не может -- я вот не буду ничего менять, а другой поток возьмёт и изменит.

Автор: ivashkanet 5.10.2007, 17:55
Цитата(iad @  5.10.2007,  17:12 Найти цитируемый пост)
не надо изыскивать красивые архитектурные решения, для обеспечения 100%-й инкапсуляции или заморачиваться на документацию, при отказе от полной реализации этой самой инкапсуляции..

Зато Вася Ламеров может спокойно удалить этот const (зачем он нужен, если компилятор на него раугается, а без него все ОК ;-)), компилятор все съест и поехало...
Цитата(iad @  5.10.2007,  17:12 Найти цитируемый пост)
Ну как мог рассказал

Нормально. Т.е. как я и думал.

Автор: iad 5.10.2007, 18:03
Цитата(mr.DUDA @  5.10.2007,  18:32 Найти цитируемый пост)
 а другой поток возьмёт и изменит.
 ну если в моем классе, мною созданный поток - я разработчик, то да.. я и дурак. А если другой товырисч извне - то фиг ему.. не выйдет. Разумеется все касаемо данной темы.
Цитата(ivashkanet @  5.10.2007,  18:55 Найти цитируемый пост)
Зато Вася Ламеров может спокойно удалить этот const (зачем он нужен, если компилятор на него раугается, а без него все ОК ;-))
 а може забаится менят smile

Автор: mr.DUDA 5.10.2007, 18:09

M
mr.DUDA
Тема раскрыта полностью. Засим, во избежание дальнейших спекуляций, прикрываю её.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)