2010-01-14 2 views
16

У меня есть пара классов, которые я хочу отметить определенным атрибутом. У меня есть два подхода. Один из них включает использование класса, расширяющего атрибуты. Другой использует пустой интерфейс:Интерфейсы или атрибуты для меток классов?

Атрибуты

public class FoodAttribute : Attribute { } 

[Food] 
public class Pizza { /* ... */ } 

[Food] 
public class Pancake { /* ... */ } 

if (obj.IsDefined(typeof(FoodAttribute), false)) { /* ... */ } 

Интерфейс

public interface IFoodTag { } 

public class Pizza : IFoodTag { /* ... */ } 
public class Pancake : IFoodTag { /* ... */ } 

if (obj is IFoodTag) { /* ... */ } 

Я не решаются использовать атрибуты в связи с его использованием Reflection. В то же время, однако, я не решаюсь создать пустой интерфейс, который действительно служит только тегом. Я испытывал стресс-тестирование, и разница во времени между ними составляет всего около трех миллисекунд, поэтому производительность здесь не поставлена.

+0

просто интересно, что вы делаете, если объект является пищей? если интерфейс IFood пуст, для чего вы их различаете? ... – serhio

+0

Если объект является продуктом питания, я бы возвратил FoodEventArguments. Если бы объект был, скажем, Beverage, я бы возвратил DrinkEventArguments. В принципе, есть общий базовый класс (скажем ConcessionStandItem), который передается в функцию. – Scott

+0

См. Также: http://blogs.msdn.com/ericlippert/archive/2009/02/02/properties-vs-attributes.aspx –

ответ

14

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

С интерфейсами это невозможно.

Я бы пошел с атрибутами.

+0

+1, это тоже точка, которую я пропустил в своем ответе. – Restuta

+1

Microsoft также рекомендует его, но они отклонились от своих рекомендаций в нескольких местах. (например, «IRequiresSessionState» и «IReadOnlySessionState» в ASP.NET). –

+1

ISerializable, я знаю. –

5

Возможно, вы ответили на свой вопрос самостоятельно. Атрибуты здесь более логичны, отражение не БОЛЬШОЙ МОНСТР С КРАСНЫМИ ГЛАЗАМИ =)

Кстати, вы можете показать код вызова, где вы определяете отмеченные интерфейсом типы? Разве вы не используете там отражение?

+3

+1 для монстров! –

+1

Нет, я просто использую оператор 'is', чтобы проверить, помечен ли данный объект интерфейсу (см. Последнюю строку примера «Интерфейс»). – Scott

+0

Спасибо, я вижу сейчас. – Restuta

0

В этом случае, как вы говорите, вы не используете интерфейс правильно.

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

7

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

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

Ваш дизайн начинается так:

interface IFood {} 

Но тогда вы решили добавить что-то там:

interface IFood { 
    int Calories { get; } 
} 

Есть также other ways расширить интерфейсы:

static class FoodExtensions { 
    public static void Lighten(this IFood self) { 
    self.Calories /= 2; 
    } 
} 
Смежные вопросы