C# и const
От: johny5 Новая Зеландия
Дата: 16.09.15 10:38
Оценка: 3 (1)
Разогрею: всё таки непонятно, как вы с этим языком работаете?


Вот, собрал модель данных:
    class ScienceModule
    {
        public int class_id;    //    ClassCategories
        public string name;
        public Dictionary<string, string> descriptions;
        public int production_cost;
        public List<int> resource_cost;
        public string tech_pic;

        //    class_ids in comment
        public int power;                    
        public int fuel_consume;            
        public int mass;                    
        public int strength;                
        public int scan_power;                
        public int scan_penetr_power;        
        public int defence_strength;        
        public int terraform_power;        
        public int improve_percent;        
        public int damage;                    
        public int self_damage;            
        public int range;                    
        public int reload_time;            
        public int precision;                
        public int affect_radius;            
        public int warheads;                
    ..
    }

    ..

    class HullSlot
    {
        public IntPoint pos;
        public int stack_num;
        public int max_mass;
        public int slot_type;
        public int direction;
        ..
    };

    class Hull
    {
        public Dictionary<string, string> descriptions;
        public List<int> resource_cost;
        public string tech_pic;
        ...
    };

    ...
    ... много ещё классов и полей

    class Model
    {
        public ResourceDefinitions            resources;

        public List<ScienceNode>            science_tree;
        public List<ScienceModule>            planet_blocks;
        public List<ScienceModule>            ship_blocks;
        public List<Hull>                hulls;

        public List<ShipDesign>                ship_designs_startup;
        public Dictionary<string, int>            fleet_amount_startup;
        public List<UniqueID>                inventions_startup;

        // group of set/update methods
        void UpdateScienceModule(ScienceModule newModule);
        ... 
    }



Пишу редактор модели. Биндю всё это к UI (WPF).
Собственно всё что хочется, выдать клиенту это всё в readonly формате. А если UI меняет что-то, связывать это через явные вызовы сеттеров в модели.

Не трогая пока сеттеры, как выдать этот класс UI-ю read only?
Re: C# и const
От: Sinix  
Дата: 16.09.15 11:00
Оценка: 14 (2) +1
Здравствуйте, johny5, Вы писали:

J>Разогрею: всё таки непонятно, как вы с этим языком работаете?

Элементарно:
1. Изучить матчасть
2. Если что-то непонятно — см п.1.
Как спросили, так и ответил


J>Не трогая пока сеттеры, как выдать этот класс UI-ю read only?

Так в readonly или "через сеттеры"?
если коротко:

1. public-поля зло. Используйте свойства.

2. Двусторонний биндинг требует реализацию INotifyPropertyChanged + ObservableCollection/IBindingList для коллекций.

3. Что именно вы имеете в виду под "ридонли"? Чтобы не изменялись поля, поля у полей, поля у объектов в списках и т.д.?
Прям из коробки такого нет и не будет, по очевидным причинам.
Не из коробки: построение больших immutable tree — это та ещё магия. Для затравки:
http://blogs.msdn.com/b/ericlippert/archive/2012/06/08/persistence-facades-and-roslyn-s-red-green-trees.aspx
https://roslyn.codeplex.com/discussions/541953

4. Вопрос очень похож на XY-problem. Давайте начнём с "Для чего тут readonly"?
Re: C# и const
От: Jack128  
Дата: 16.09.15 12:28
Оценка: +1
Здравствуйте, johny5, Вы писали:

Мутно ты описал, но есть подозрение, что тебе OneWayToSource Binding нужен.

ЗЫ Причем тут философия ??
Re[2]: C# и const
От: johny5 Новая Зеландия
Дата: 16.09.15 12:33
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, johny5, Вы писали:


S>если коротко:

S>1. public-поля зло. Используйте свойства.

Пока не вижу выгоды от проперти вообще и в данном случае в частности. Хотя видел народ предлагает делать { get; private set; }, только это не удобно в моём случае. Я бы ещё покопал в сторону public/internal, хотя вроде бы чтобы internal нормально работал, мне нужно будет собирать отдельную assembly?


S>3. Что именно вы имеете в виду под "ридонли"? Чтобы не изменялись поля, поля у полей, поля у объектов в списках и т.д.?

Да, обыкновенная Deep constness.

S>Прям из коробки такого нет и не будет, по очевидным причинам.

Что за очевидные причины?

S>Не из коробки: построение больших immutable tree — это та ещё магия. Для затравки:


Почитаю ссылочки завтра. Как раз затравливаю, чтобы народ поучил меня уму-разуму, мож пойму чего. Уже 3й раз штурмую эту "крепость" и, пока на уровне скриптиков или там коннекта с DB, C# — прекрасный язык. Начинаешь архитектурить, сразу залазишь по пояс.


S>4. Вопрос очень похож на XY-problem. Давайте начнём с "Для чего тут readonly"?


Ну убедили, давайте поиграем и в эту игру, в параллель.
Я пишу UI редактор этой модели: в частности, добавить "игровую науку", убавить, изменить её значения. Я решил (вроде как по MVVM?) что будет у меня View class, который будет уметь отображать эту модель в редакторе. При переключении всяких табов или выбора подменю, UI должен сам уметь вытягивать нужные данные из модели и показывать на экране. При этом я хотел гарантировать, что UI (не доверяю WPF) случайно не смог изменить саму модель. С какимнть int переменной оно вполне сможет сбиндиться двусторонне. Ну или чтобы я сам впопыхах не впилил прямые изменения модели прямо в код.

Все изменения модели будут проходить через другой (ViewModel?) класс, оно будет подписываться на всякие нужные кнопки само и менять модель. Дополнительно ViewModel будет следить у меня за Undo/Redo, Save/Load и прочие.
Re[2]: C# и const
От: johny5 Новая Зеландия
Дата: 16.09.15 12:37
Оценка:
Здравствуйте, Jack128, Вы писали:

J>ЗЫ Причем тут философия ??


Наверно потому что хочу получить больше конструктива чем это было бы в священных войнах.
Re: C# и const
От: mogikanin Россия  
Дата: 16.09.15 13:00
Оценка: 4 (1) +3
Здравствуйте, johny5, Вы писали:

J>Не трогая пока сеттеры, как выдать этот класс UI-ю read only?


Очевидно, выставить IsReadOnly=true у соответствующих контролов. Либо поставить BindingMode=OneWay\OneTime
Re[3]: C# и const
От: Sinix  
Дата: 16.09.15 14:02
Оценка: 16 (2)
Здравствуйте, johny5, Вы писали:


J>Пока не вижу выгоды от проперти вообще и в данном случае в частности.

Если коротко — с полями вы в принципе не имеете никакого контроля за возможностью изменения объектов.
Классика от Joe Duffy:
        struct S
        {
            public readonly int X;

            public S(int x) { X = x; }

            public void MultiplyInto(int c, out S target)
            {
                System.Console.WriteLine(this.X);
                target = new S(X * c);
                System.Console.WriteLine(this.X); // same? it is, after all, readonly.

            }
        }
        static void Main(string[] args)
        {
            S s = new S(42);
            s.MultiplyInto(10, out s);
            Console.ReadKey();
        }


S>>Прям из коробки такого нет и не будет, по очевидным причинам.

J>Что за очевидные причины?
Для гарантированно неизменяемого графа вам придётся создать свою иерархию типов, в которых нет изменяемых методов/сеттеров/коллекций. Плюс, не забыть тонну хелперов для обновления отдельных узлов графа (аля person = person.WithName("XYZ") вместо person.Name = "XYZ").

Это реально адова работа, а биндить такой граф к UI — гадость ещё большая. Нужны очень веские причины, чтобы такой изврат делать.


S>>4. Вопрос очень похож на XY-problem. Давайте начнём с "Для чего тут readonly"?

J>Ну убедили, давайте поиграем и в эту игру, в параллель.
Так оно работает Проблема у вас не в "нужно immutable object tree", а в "нужно подстраховаться от случайного двустороннего биндинга" плюс "нужно прикрутить undo-redo к произвольному графу объектов".
Первое делается на порядок проще — проверками в обработчике для INotifyPropertyChanged и/или выставлением IsReadOnly = true в стилях контролов.

Второе (undo-redo) надо очень аккуратно продумывать и закладывать в код с самого начала, особенно с учётом того, что данные могут меняться асинхронно (в фоновых операциях).
Основных вариантов всего два: или очередь из undo-redo-команд, или всё тот же граф immutable-объектов, но это в теории. На практике я не видел ни одного красивого удобного универсального решения. Вне зависимости от ЯП.
Re: C# и const
От: Vladek Россия Github
Дата: 24.10.15 15:11
Оценка:
Здравствуйте, johny5, Вы писали:


J>Разогрею: всё таки непонятно, как вы с этим языком работаете?


В Visual Studio обычно.

J>Вот, собрал модель данных:

J>Пишу редактор модели. Биндю всё это к UI (WPF).
J>Собственно всё что хочется, выдать клиенту это всё в readonly формате. А если UI меняет что-то, связывать это через явные вызовы сеттеров в модели.
J>Не трогая пока сеттеры, как выдать этот класс UI-ю read only?

Очевидно, поменять его на структуру! Не вижу в этих классах ничего кроме данных — это не объекты, это структуры данных. Правда не помню, работает ли биндинг для полей структур, кажется он работает только для свойств классов. А для всех других требований структуры тут подходят — они будут копироваться, а не передаваться по ссылке.
Re[3]: C# и const
От: Vladek Россия Github
Дата: 24.10.15 15:14
Оценка:
Здравствуйте, johny5, Вы писали:

J>Ну убедили, давайте поиграем и в эту игру, в параллель.

J>Я пишу UI редактор этой модели: в частности, добавить "игровую науку", убавить, изменить её значения. Я решил (вроде как по MVVM?) что будет у меня View class, который будет уметь отображать эту модель в редакторе. При переключении всяких табов или выбора подменю, UI должен сам уметь вытягивать нужные данные из модели и показывать на экране. При этом я хотел гарантировать, что UI (не доверяю WPF) случайно не смог изменить саму модель. С какимнть int переменной оно вполне сможет сбиндиться двусторонне. Ну или чтобы я сам впопыхах не впилил прямые изменения модели прямо в код.

J>Все изменения модели будут проходить через другой (ViewModel?) класс, оно будет подписываться на всякие нужные кнопки само и менять модель. Дополнительно ViewModel будет следить у меня за Undo/Redo, Save/Load и прочие.


Это мне напоминает MVC:

Re: C# и const
От: xy012111  
Дата: 24.10.15 16:47
Оценка:
Здравствуйте, johny5, Вы писали:

J>Разогрею: всё таки непонятно, как вы с этим языком работаете?

J>Вот, собрал модель данных:
J>    class ScienceModule
J>    {
J>        public int class_id;    //    ClassCategories
J>    ..
J>    ...
J>    ... много ещё классов и полей

J>Пишу редактор модели. Биндю всё это к UI (WPF).

Очень интересно, расскажите-ка к какому ЮАЮ и как именно вы это так биндите, что у вас поля биндятся? Биндинг, мне кажется, по-дефолту, работает именно со свойствами, а поля игнорирует Тут или вы где-то лукавите или, простите, если я чего перепутал

J>Собственно всё что хочется, выдать клиенту это всё в readonly формате.


Легче лёгкого. Если интерфейс у вас работает только посредством биндинга, то отдавайте ему просто object с таким тайп-дескриптором, который не позволит через биндинг менять свойства.

J>А если UI меняет что-то, связывать это через явные вызовы сеттеров в модели.


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

J>Не трогая пока сеттеры, как выдать этот класс UI-ю read only?


Курите TypeDescriptor. Какая-то работа с биндингом без понимания этой кухни — это примерно как дать ребёнку поиграть с заряженным пистолетом.

UPD: Кстати вот же
Автор: _FRED_
Дата: 28.03.07
есть пример того, как оно может работать: как свойство то делается ридонли, то возвращается обратно. В public override void SetValue пропертидескриптора можно отловить изменение значения свойства, но это не единственный способ, разберитесь с тем, как TypeDescriptor работает и что там есть и найдёте более подходящий для вашего случая способ.
Отредактировано 24.10.2015 18:32 xy012111 . Предыдущая версия .
Re: C# и const
От: Sinatr Германия  
Дата: 26.10.15 08:33
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:

J>Пишу редактор модели. Биндю всё это к UI (WPF).

J>Собственно всё что хочется, выдать клиенту это всё в readonly формате. А если UI меняет что-то, связывать это через явные вызовы сеттеров в модели.

Сначала прочитайте про MVVM. В wpf самое то.

Далее напишите ViewModel для вашей модели и для подмоделей. Это одна из задач ViewModel — обеспечивать целостность данных, чтобы какой-нибудь дизайнер, не особо разбирающией в нюансах, запилил View и не подпортил данные Model'и.

Модель
class Model
{
    public List<ScienceModule> planet_blocks;
    ...
}


оборачивается в что-то вроде
class ViewModel: INotifyPropertyChanged
{
    ObservableCollection<ViewModelScience> _planetBlocks;
    public ObservableCollection<ViewModelScience> PlanetBlocks
    {
        get { return _planetBlocks; }
        set
        {
            _planetBlocks = value;
            OnPropertyChanged(); // [CallerMemberName]
        }
    }

    public ObservableCollection<ViewModelScience> ScienceTree {get;}  // только геттер, инстанциируется конструктором

    public ObservableCollection<ViewModelScience> ShipBlocks {get; private set;}  // может быть изменен во ViewModel, при этом необходимо вызвать OnPropertyChanged(nameof(ShipBlock)] самостоятельно
}


Все изменения с коллекциями производятся через методы ViewModel, например, команда CommandAddPlanet проверит на дупликаты и т.д. PlanetBlocks используется для биндинга к ItemsSource какого-либо контейнера.

Во View прописываются DataTemplate задающий отображение (другой View) для ViewModelScience.

Эта иерархия ViewModel и обеспечивает целостностью данных.
---
ПроГLамеры объединяйтесь..
Re[2]: Вопрос снят.
От: johny5 Новая Зеландия
Дата: 27.10.15 10:16
Оценка:
Здравствуйте, Sinatr, Вы писали:

Спасибо за развёрнутый ответ. Хоть это уже и немного некропостинг.

Так по сути и сделал, единственно чтобы сэкономить себе пальцы и не писать под каждое проперти такой классик, наклепал его полиморфным через reflection, оно получает рефлекшн ссылку на поле и понеслась пляска.
Такой подход помог мне изящно впилить undo/redo, буквально в 10 строках. На OnPropertyChanged в модель складывались 2 undo/redo команды, которые просто заполняли редактируемое поле старым либо новым значением. Так изящно что я не удержусь и приведу весь его код прямо тут:
        private void OnModuleChanged(ScienceModule changedModule, FieldInfo field, object newVal)
        {
            object oldVal = field.GetValue(changedModule);

            //    we don't modify directly, but instead create undo/redo commands
            Action redo = () => { field.SetValue(changedModule, newVal); this.OnScienceModuleUpdated(changedModule); };
            Action undo = () => { field.SetValue(changedModule, oldVal); this.OnScienceModuleUpdated(changedModule); };

            m_model.SubmitChange(undo, redo);
        }


Конст действительно перестал быть необходимостью, хотя его наличие чуточку бы помогло добавить компайл-тайм проверок что я не оступился во ViewModel имплементации.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.