Пользовательский атрибут для обеспечения инкапсуляции - PullRequest
2 голосов
/ 02 июля 2010

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

[RestrictToProperty("Foo")]
private object _foo;
public object Foo
{
    get { return _foo; }
    set
    {
        _foo = value;
        OnFooChanged(EventArgs.Empty);
    }
}
public object NotFoo
{
    get { return _foo; }  // Warning
    set { _foo = value; } // Warning
}
public void Bar()
{
    _foo = new object();  // Warning
}

// Warning: 'MyClass._foo' should not be used outside of property 'Foo'

Я верю, что это возможно, потому что Obsolete делает то же самое.

[Obsolete]
private object _foo;
public void Bar()
{
    _foo = new object(); // Warning: 'MyClass._foo' is obsolete
}

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

Ответы [ 5 ]

3 голосов
/ 02 июля 2010

Нет, это невозможно. ObsoleteAttribute имеет специальное упоминание в спецификации C # относительно того, как на это реагирует сам компилятор.

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

public class Test
{
  public object Foo { get; set; }
}

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

public class Test
{

  private PrivateMembers Members { get; set; }

  public object Foo
  {
    get
    {
      return Members.Foo;
    }
    set
    {
      Members.Foo = value;
      // Do something else here.
    }
  }

  private class PrivateMembers
  {
    public object Foo { get; set; }
  }
}
2 голосов
/ 02 июля 2010

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

1 голос
/ 02 июля 2010

Немного не по теме, но вы можете (ab) использовать атрибут Obsolete для достижения того, что вам нужно.

Пометить вспомогательное поле как устаревшее, чтобы при попытке доступа к нему компилятор генерировал предупреждениеи затем подавляет эти предупреждения в свойстве getter / setter.(Соответствующие предупреждения: CS0612 и CS0618 .)

[Obsolete("Backing field should not be used outside of property")]
private object _foo;

public object Foo
{
    #pragma warning disable 612, 618
    get { return _foo; }
    set
    {
        _foo = value;
        OnFooChanged(EventArgs.Empty);
    }
    #pragma warning restore 612, 618
}

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

1 голос
/ 02 июля 2010

К сожалению, это невозможно. Возможно, вы захотите изучить PostSharp , который является As-Oriented IL-weaver для .NET - в основном он позволяет вашему исходному коду пройти дополнительный уровень компиляции, который может внедрить все дополнительные церемонии.

0 голосов
/ 02 июля 2010

Нет, я думаю, что невозможно на уровне языка .Хотя вы можете контролировать доступ к свойству через get и set методы доступа, вы не можете контролировать доступ к полю.В конце концов, это основное различие между полями и свойствами, не так ли.

Я думаю, ObsoleteAttribute получает специальную обработку в Visual Studio.VS знает, что он должен выдавать предупреждение всякий раз, когда сталкивается с созданием экземпляра типа, отмеченного этим атрибутом.Поэтому, я думаю, вы могли бы реализовать свой RestrictToPropertyAttribute вместе с помощью какого-то расширения / плагина Visual Studio .


PS: Обратите внимание, что в ваших примерах кода, вам не нужно явное поле поддержки в первую очередь! Если ваши средства доступа к свойствам не содержат никакой дополнительной логики, вы также можете написать:

public int SomeProperty { get; set; }

и вспомогательное поле для SomeProperty будет создано для вас автоматически (но оно скрыто, поэтому вы не можете получить к нему доступ любым другим способом, кроме как через свойство - т. Е. Именно то, что вы пытаетесь достичь).

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