Есть ли лучший способ написания этого кода?

#c# #delegates #.net-micro-framework

#c# #делегаты #.net-микро-фреймворк

Вопрос:

У меня есть класс с перечислением, DoStuff содержащим значения before , after или none . Эти имена не являются истинными именами, но это передает суть. У класса есть метод foo .

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

 public [type] MyProperty {
    get {
        if(enumValue == DoStuff.Before)
            foo();

        [type] result = //Do calculations here

        if(enumValue == DoStuff.After)
            foo();

        return resu<
    }
}
  

Есть ли способ абстрагироваться от этих вызовов до / после вычисления? В настоящее время я могу придумать два решения:

  • Создайте частный метод, который принимает делегат и вызывает foo в соответствующем месте. Осложняется отсутствием дженериков на платформе, для которой я это пишу.

  • Создайте не подлежащий удалению базовый класс без вызова оболочки и создайте подкласс Before и After, который обращается к свойствам базового класса, с вызовом в соответствующем месте

Существует ли хорошо известный шаблон для такого рода структуры?

Комментарии:

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

2. @Reddog: foo() это не вызов, изменяющий состояние.

Ответ №1:

Создайте метод с таким синтаксисом:

 delegate void Handler();

void DoHandler(Handler handler)
{
        if(enumValue == DoStuff.Before)
            foo();

        handler();

        if(enumValue == DoStuff.After)
            foo();
}
  

Тогда в вашем свойстве

 public [type] MyProperty 
{
    get 
    {
        [type] result = default(type); 
        DoHandler(() => 
        {
            int a = 5;
            int b = 6;
            result = a   b;
        });
        return resu<
    }
}
  

Комментарии:

1. С этим связаны две проблемы. Во-первых, это требует от меня написания DoHandler функции для каждого типа возвращаемого значения, что делает код более беспорядочным, а не более чистым. Во-вторых, я сказал в вопросе, что у меня нет поддержки дженериков, так что нет Func<type> .

2. ну, тогда вы можете сделать это немного по-другому. Тогда я его модифицирую.

3. Можете ли вы выполнять замыкания внутри лямбд в c #?

4. Замыкания, как в { } ? Лямбда-выражение — это функция с кратким описанием, поэтому все, что вы можете делать с функциями, вы можете делать с лямбда-выражением (и даже больше с лямбда-выражением, как вы можете видеть, оно присваивает переменной вне области видимости функции). Немного модифицировал лямбда, так что, возможно, это может вам помочь.

Ответ №2:

Я был бы склонен создать событие / делегат до и после и щелкнуть foo () в соответствующем месте, вероятно, там, где вы устанавливаете enumValue прямо сейчас. Затем вызовите:

 get {
   BeforeDelegate();
   // Do calcs
   AfterDelegate();
}
  

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

Примечание: Если у меня есть средство получения, выполняющее такую логику, я, скорее всего, помещу это в метод. Это с меньшей вероятностью удивит людей. Методы намекают на то, что я, вероятно, сделал что-то под капотом, чтобы получить значение, которое вы просили, помимо простого отображения скалярного значения.

Комментарии:

1. Код предназначен для взаимодействия с аппаратным обеспечением, поэтому представляется разумным использовать свойства (поскольку они являются свойствами аппаратного обеспечения). Аппаратное обеспечение имеет три режима: обновление непрерывно ( Continuous , он же DoStuff.None ), обновление по запросу ( Standby , он же DoStuff.Before ) и обновление после чтения ( Query , он же DoStuff.After ).

2. Хммм… Мне все равно было бы удобнее с GetPropertyValue() вызовом, но для начала это довольно придирчивая вещь. Есть ли что-нибудь еще, кроме foo() того, что происходит в точках принятия решения? Я не думаю, что это вопрос не столько «наилучшего шаблона», сколько «краткой семантики». Если это все, что происходит, и это единственное свойство, в котором это происходит, тогда подход enum довольно понятен. Если это происходит повсеместно, то я был бы склонен использовать подход делегирования / события.

Ответ №3:

Я думаю, что лучше поместить значение enum в отдельный класс, который имеет 1 свойство с именем EnamumValue и к событию до и после, и обрабатывать это до события в классе, который использует класс enamvalue, когда изменения enumvalue запускают соответствующее событие

 public class EnumValueClass
{

    public event BeforeDelegate OnBefore();
    public event AfterDelegate OnAfter();
    private EnumType enumValue;
    public EnumType EnumValue
    {
        get {
            return enumValue;
        }
        set{
            this.enumValue = value;
            if(enumValue == DoStuff.Before)
                if(OnBefore!=null)
                    OnBefore();

            if(enumValue == DoStuff.After)
                if(OnAfter!=null)
                    OnAfter();
        }


    }
}
  

Комментарии:

1. Это не соответствует контракту вызова. Во-первых, OnAfter это та же функция, что и OnBefore . Что еще более важно, метод foo должен вызываться либо до, либо после большинства обращений к свойствам. Его не нужно вызывать при изменении режима.