Избегать маркерных интерфейсов для пользовательских атрибутов для словаря? - PullRequest
1 голос
/ 28 января 2012

Вот пример того, как я избегаю маркерных интерфейсов.

public class AssignableAttribute : Attribute { }

[Assignable]  
public class Foo   
{      
   ...  
}  

[Assignable]  
public class Bar
{      
   ...  
}  

И я пытаюсь добавить его в словарь Почему я не могу кодировать словарь, подобный этому, и как исправитьit?

Dictionary<string, AssignableAttribute> dictionary = new ...();
dictionary.Add("foo", new Foo());
dictionary.Add("bar", new Bar());

Избегайте использования маркерных интерфейсов (интерфейсов без элементов).

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

http://msdn.microsoft.com/en-us/library/ms229022.aspx

Ответы [ 5 ]

3 голосов
/ 23 мая 2014

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

Это ключ.Когда вы пытаетесь использовать подобный шаблон, вы используете проверку во время компиляции.Вы могли бы отложить проверку во время выполнения с Dictionary<string, Object>, но я не думаю, что кто-то предпочел бы это без каких-либо особых обстоятельств - это дополнительные усилия и возможность ошибок без какой-либо реальной выгоды.

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

0 голосов
/ 28 января 2012

Звучит так, будто вы не используете доступную вам среду в полной мере. Решение проблемы отсутствия интерфейсов маркеров состоит в том, чтобы иметь интерфейс, который не является маркером .

РЕДАКТИРОВАТЬ Мне немного непонятно, что делает атрибут Assignable, я полагаю, это своего рода преобразование или десериализация?

Как насчет этого: сделать атрибут Assignable в универсальном интерфейсе IAssignableFrom<T>.

interface IAssignableFrom<T> {
  void AssignFrom(T source);
}

public class Bar : IAssignableFrom<Foo> {
  public void AssignFrom(Foo foo){
     //implementation of assignment here
  }
}

public class Baz : IAssignableFrom<Foo> {
  public void AssignFrom(Foo foo){
     //implementation of assignment here
  }
}

public class Foo : IAssignableFrom<Foo> {
  public void AssignFrom(Foo foo){
     //implementation of assignment here
  }
}

public class Program {
  public static void Main(string[] args){
    IDictionary<string, IAssignableFrom<Foo>> dictionary = new Dictionary<string, IAssignableFrom<Foo>>;

    dictionary.Add("foo", new Foo());
    dictionary.Add("bar", new Bar());
    dictionary.Add("baz", new Baz());
  }
}
0 голосов
/ 28 января 2012

Тип не имеет ничего общего с атрибутами.

Вы должны использовать интерфейс IFoo, например,

 interface IFoo 
 {
     // various methods
 }

 public class Foo : IFoo
 {
 }

 public class Bar : IFoo { }

и словарь

 Dictionary<string, IFoo> dictionary = new ...();
 dictionary.Add("foo", new Foo());
 dictionary.Add("bar", new Bar());
0 голосов
/ 28 января 2012

Если вы не хотите использовать интерфейс, вы можете создать словарь объектов и просто проверить, задан ли тип AssignableAttribute, прежде чем добавлять его в свой словарь

Dictionary<string, object> dictionary = ...;


private void AddAssignable(object assignableObject)
{
     var type = assignableObject.GetType();
     if (type.GetCustomAttributes(typeof(AssignableAttribute), true) == null)
        return;

     dictionary.Add(type.Name, assignableObject);
}
0 голосов
/ 28 января 2012

Вы не можете выразить что-то вроде «Словарь типов, которым назначен определенный атрибут». Тип предоставляет вам операции, которые вы можете вызывать для него. Помещая атрибут в тип, вы не добавляете к нему никаких операций - вы просто предоставляете некоторые дополнительные метаданные. Если вы хотите избежать маркерных интерфейсов, вам нужно немного уточнить, какую именно проблему вы пытаетесь решить с помощью этого.

Редактировать

Атрибуты не изменяют поведение типа (они не добавляют дополнительных операций и не изменяют реализацию типа). Они полностью ортогональны вашей иерархии классов. Они в основном используются, поэтому некоторые фреймворки могут во время выполнения вывести какое-то дополнительное значение о типе или его членах (например, xml serialzier может быть передан через атрибут, каким образом можно сериализовать элементы certina или игнорировать определенные элементы). Вы не можете использовать атрибуты в качестве ограничений типов компиляции для обобщений в том смысле, что вы разрешаете всем типам, к которым прикреплен определенный атрибут (компилятор не может это проверить в принципе).

...