2009-03-15 5 views
8

Есть ли способ получить доступ к полю поддержки для свойства, чтобы сделать проверку, изменить отслеживание и т. Д.?Признание поля поддержки в авто property

Возможно ли следующее: Если нет, то какие-либо планы по его использованию в .NET 4/C# 4?

public string Name 
{ 
    get; 
    set 
    { 
     if (value != <Keyword>) 
     { 
      RaiseEvent(); 
     } 
     <Keyword> = value; 
    } 
} 

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

В приведенном выше примере, доступ к полю подложки будет область видимости собственности, таким образом, предотвращая обход проверки собственности, отслеживание изменений и т.д.

Edit: Я изменил < Резервное поле> для < Ключевого слова >. Я бы предложил новое ключевое слово, подобное значению. Поле было бы неплохо, хотя я уверен, что он используется во множестве существующего кода.

ответ

3

Прочитав ваши комментарии в ответе Мехрдада, я думаю, что я понимаю вашу проблему немного лучше.

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

Я предлагаю следующую стратегию. Напишите общий класс, который представляет ValidatedValue. Этот класс содержит только значение подкладочного и позволяет только доступ/мутации с помощью получения и установок методов. Делегат передается 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); } 
    } 
} 

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

+0

Это приятное решение, но много кода, в котором доступ к полю точно так же, как мы получаем новое значение в сеттере с ключевым словом value быть более кратким и элегантным. –

+2

Возможно, вы можете сделать синтаксис более приятным, добавив operator = и coersion в T в класс ValidatedValue. В основном вы хотите, чтобы он вел себя как ValidatedValue. - это T. –

1

Если вы сделаете это, то почему вы используете авто свойства ?!

Простая собственность сделала это еще раз в 1.0. Я не думаю, что имеет смысл добавить сложность в язык для каждого конкретного случая. Вам либо нужно свойство, чтобы сделать обычную модель хранения/извлечения, либо потребовать больше. В последнем случае будет выполняться нормальное свойство.

+0

Выгода авто свойств является то, что вы вынуждены использовать свойство, а не поле подложки из методов в классе. –

+0

Я не вижу никакой выгоды в том, чтобы заставить класс не использовать то, что он объявляет. Вот почему у нас не так много модификаторов доступа «private». –

+0

Я знаю, но в некоторых случаях это просто хранилище. Нет другой причины объявлять об этом, и вы хотите контролировать доступ к этому хранилищу независимо от того, где он находится. –

13

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

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

+0

Я хотел бы использовать использование свойства из класса, в котором находится свойство. Я не хочу, чтобы код в классе напрямую обращался к полю. –

+3

Занятия должны быть в состоянии доверять себе, чтобы правильно обращаться со своими рядовыми. –

+2

IMO это ответ на * актуальный * вопрос. Ответ, отмеченный как ответ, является ответом на отдельный тангенциальный вопрос:/ – Catskul

1

Вы не можете этого сделать, я боюсь. Это одна из причин, по которой я начал писать MoXAML Power Toys, чтобы обеспечить возможность преобразования автоматических свойств в свойства «Уведомлять».

+0

Выглядит интересно.Все еще не решает проблему наличия лежащего вокруг поля, которое не должно быть доступно, кроме как из сферы действия свойства. –

6

Как MSDN состояний:

«В C# 3.0 и позже, авто Реализуемого свойство делает свойство декларирования более кратким, когда нет дополнительной логики не требуется аксессорах собственности Они также позволяют. клиентский код для создания объектов . Когда вы объявляете свойство как , показанное в следующем примере, компилятор создает приватное, анонимное поле базы данных может быть доступно только через пункт получения и установки аксессуаров. "

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

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

+0

У меня создалось впечатление, что только причина для искаженного имени - убедиться, что он уникален. Не знаю, как это происходит. Он добавляет в странные символы, которые недопустимы для имени переменной. –

+0

То, что я не понимаю, - это то, почему анонимное поле даже нуждается в имени ... –

2

Нет, но вы можете в подклассе:

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; 
     } 
    } 
}