Search code examples
c#genericscovariancecontravariance

Storing disparate generics in a single enumerable


Given a generic attribute class:

public class Attribute<T>
{
  string Name { get; set; }
  T Value { get; set; }
}

Is there a way to have an object that contains an enumerable containing various types of that generic (for example int, string, datetime).

public class AttributableObject
{
  IEnumerable<???> attributes { get; set;}
}

Is there anyway to do this that won't run into variance problems?


Solution

  • The typical approach is to have the generic class derive from a non-generic base class (or interface,) and then have an enumerable of that type:

    public abstract class AttributeBase
    {
        // Non-generic stuff here
    }
    
    public class Attribute<T> : AttributeBase
    {
        // Generic stuff here
    }
    

    Then you can declare:

    IEnumerable<AttributeBase> attributes;
    

    Of course you'll still need to know what the type of each element is if you'd like to use any of the generic features (like actually getting the value.)

    Note that covariance/contravariance won't help here, since the Value property is both settable and gettable, and thus the generic parameter is invariant (not to mention that it's a generic class, so it can't be made co/contra-variant anyway.)