views:

132

answers:

4

I have a couple of classes that I wish to tag with a particular attribute. I have two approaches in mind. One involves using an Attribute-extending class. The other uses an empty interface:

Attributes

public class FoodAttribute : Attribute { }

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

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

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

Interface

public interface IFoodTag { }

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

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

I'm hesitant to use the attributes due to its usage of Reflection. At the same time, however, I'm hesitant on creating an empty interface that is only really serving as a tag. I've stress-tested both and the time difference between the two is only about three milliseconds, so performance is not at stake here.

+8  A: 

Well, with attributes, you can always create the attribute in such a way that its function doesn't propagate to descendant types automatically.

With interfaces, that's not possible.

I would go with attributes.

Lasse V. Karlsen
+1, this is also point I missed in my answer.
Restuta
Microsoft also recommends it but they have diverged from their own recommendations in several places. (e.g. `IRequiresSessionState` and `IReadOnlySessionState` in ASP.NET).
Mehrdad Afshari
ISerializable, I know.
Lasse V. Karlsen
`ISerializable` is not a marker interface. It contains a member (`GetObjectData`). Actually they have done `SerializableAttribute` correctly.
Mehrdad Afshari
Ok, my bad then :P
Lasse V. Karlsen
That is something that I hadn't thought of. Thanks for pointing it out.
Secret Agent Man
+5  A: 

You probably have answered on you question by your own. Attributes is more logical here, reflection is not a BIG MONSTER WITH RED EYES =)

btw, can you show calling code, where you determine marked with interface types? Aren't you using reflection there?

Restuta
+1 for monsters!
Jarrett Meyer
Nah, I'm just using the 'is' operator to check whether the given object is marked with an interface (see last line of 'Interface' example).
Secret Agent Man
Thanks you, I see now.
Restuta
@DePouw: this is a masked reflection, anyway...
serhio
A: 

In this case, as you say, you're not using an interface correctly.

What's wrong with using reflection the get you attributes? The usual answer is performance but that is generally not a real issue in nearly all cases.

Charlie
A: 

I'll have to say otherwise. I think that, for your example, a marker interface makes more sense.

That's because it seems very likely that you might one day add some members to IFood.

Your design starts like this:

interface IFood {}

But then you decide to add something there:

interface IFood {
  int Calories { get; }
}

There are also other ways to extend interfaces:

static class FoodExtensions {
  public static void Lighten(this IFood self) { 
    self.Calories /= 2;
  } 
}
Jordão