Доступ к полю поддержки в свойстве auto
-
19-08-2019 - |
Вопрос
Есть ли способ получить доступ к вспомогательному полю для свойства для проверки, отслеживания изменений и т. д.?
Возможно ли что-то вроде следующего? Если нет, то есть ли планы сделать это в .NET 4 / C # 4?
public string Name
{
get;
set
{
if (value != <Keyword>)
{
RaiseEvent();
}
<Keyword> = value;
}
}
Основная проблема, с которой я столкнулся, заключается в том, что использование автоматических свойств не обеспечивает той же гибкости при проверке и т. д., что и свойство с явным вспомогательным полем. Однако в некоторых ситуациях явное поле поддержки имеет недостаток, заключающийся в том, что он позволяет классу, в котором он находится, получить доступ к полю поддержки, когда он должен получить доступ и повторно использовать проверку, отслеживание изменений и т. Д. Свойства, как и любой другой класс, к которому может обращаться собственность внешне.
В приведенном выше примере доступ к полю поддержки будет ограничен для свойства, что предотвращает обход проверки свойства, отслеживание изменений и т. д.
Изменить: я изменился < Защитное поле & Gt; к & л; Ключевое слово & Gt ;. Я бы предложил новое ключевое слово, похожее на значение. field подойдет, хотя я уверен, что он используется во многих существующих кодах.
Решение
Прочитав ваши комментарии в ответе Мехрдада, я думаю, что немного лучше понимаю вашу проблему.
Похоже, что вы обеспокоены возможностью разработчика получить доступ к закрытому состоянию в классе, который они пишут, в обход вашей логики проверки и т. д. Это говорит о том, что состояние вообще не должно содержаться в классе. р>
Я бы предложил следующую стратегию. Напишите универсальный класс, который представляет ValidatedValue. Этот класс содержит только значение поддержки и разрешает доступ / мутацию только через методы get и set. Делегат передается в ValidatedValue для представления логики проверки:
public class ValidatedValue< T >
{
private T m_val;
public ValidationFn m_validationFn;
public delegate bool ValidationFn( T fn );
public ValidatedValue( ValidationFn validationFn )
{
m_validationFn = validationFn;
}
public T get()
{
return m_val;
}
public void set(T v)
{
if (m_validationFn(v))
{
m_val = v;
}
}
}
Конечно, вы можете добавить больше делегатов по мере необходимости (например, для поддержки уведомления до / после изменения).
Теперь ваш класс будет использовать ValidatedValue вместо резервного хранилища для вашей собственности.
В приведенном ниже примере показан класс MyClass с целым числом, значение которого не превышает 100. Обратите внимание, что логика для выброса исключения находится в MyClass, а не в ValidatedValue. Это позволяет вам выполнять сложные правила проверки, которые зависят от другого состояния, содержащегося в MyClass. Лямбда-нотация использовалась для создания делегата валидации - вместо этого вы могли бы привязаться к функции-члену.
public partial class MyClass
{
private ValidatedValue<int> m_foo;
public MyClass()
{
m_foo = new ValidatedValue<int>(
v =>
{
if (v >= 100) RaiseError();
return true;
}
);
}
private void RaiseError()
{
// Put your logic here....
throw new NotImplementedException();
}
public int Foo
{
get { return m_foo.get(); }
set { m_foo.set(value); }
}
}
Надеюсь, это поможет - немного не в тему оригинала, но я думаю, что это больше соответствует вашим реальным проблемам. То, что мы сделали, это взяли логику проверки из свойства и поместили ее в данные, где вы и хотели.
Другие советы
Нет, нет. Если вы хотите получить доступ к полю поддержки, не используйте автоматические свойства и сверните свои собственные.
Я согласен, что было бы здорово иметь поле, доступное только для свойства, а не для остальной части класса. Я бы использовал это все время.
Как MSDN заявляет:
& "В C # 3.0 и более поздних версиях реализовано автоматически свойства делают объявление свойства более лаконично, когда нет дополнительной логики требуется в свойствах доступа. Они также позволяют клиентскому коду создавать объекты Когда вы объявляете свойство как показано в следующем примере, компилятор создает приват, аноним поле доступа может быть доступно только через собственность получить и установить аксессоров Quot. &;
Поскольку у вас есть дополнительная логика в средствах доступа, использование автоматически реализуемых свойств не подходит для вашего сценария.
Несмотря на то, что поле поддержки существует, ему присваивается искаженное имя, чтобы вам было легче ссылаться на него - идея в том, что вы никогда не ссылаетесь на поле напрямую . Ради интереса, вы можете использовать Reflector для дизассемблирования вашего кода и обнаружения имени поля, но я бы порекомендовал вам не использовать поле напрямую, так как это имя действительно может быть изменчивым, поэтому ваш код может сломаться в любое время.
Нет, но вы можете в подклассе:
public class Base
{
public string Name
{
get;
virtual set;
}
}
public class Subclass : Base
{
// FIXME Unsure as to the exact syntax.
public string Name
{
override set
{
if (value != base.Name)
{
RaiseEvent();
}
base.Name = value;
}
}
}
Если вы собираетесь это сделать, почему вы используете свойства авто?!
Простое свойство сделало это еще в 1.0. Я не думаю, что имеет смысл добавлять сложность к языку для каждого особого случая. Вам либо нужно свойство, чтобы делать простые модели хранения / извлечения, либо вам нужно нечто большее. В последнем случае подойдет обычное свойство.
Боюсь, ты не можешь этого сделать. Это одна из причин, по которой я начал писать MoXAML Power Toys , чтобы преобразовать автоматические свойства в свойства уведомлений.