#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
должен вызываться либо до, либо после большинства обращений к свойствам. Его не нужно вызывать при изменении режима.