views:

148

answers:

2

I have a two generic abstract types: Entity and Association.

Let's say Entity looks like this:

public class Entity<TId>
{ 
//...
}

and Association looks like this:

public class Association<TEntity, TEntity2>
{
//...
}

How do I constrain Association so they can be of any Entity?

I can accomplish it by the following:

public class Association<TEntity, TId, TEntity2, TId2>
     where TEntity : Entity<TId>
     where TEntity2: Entity<TId2>
{
//...
}

This gets very tedious as more types derive from Association, because I have to keep passing down TId and TId2. Is there a simpler way to do this, besides just removing the constraint?

+7  A: 

This problem is usually solved by having your generic class (Entity<TId>, in this case) inherit from a common non-generic class.

public abstract class EntityBase
{

}

public class Entity<TId> : EntityBase
{

}

This will allow you to do:

public class Association<TEntity, TEntity2>
    where TEntity : EntityBase
    where TEntity2 : EntityBase
{

}

Edit

If having them inherit from a common class is an issue, then this could be easily done with an interface as well.

Adam Robinson
Very nice!! +1.
Nayan
Yeah, I'd already come to the conclusion that an interface would suit my needs best, except I need to readjust my interfaces to have a non-generic base! I was hoping there'd be a neat language trick, but alas...
HackedByChinese
@HackedByChinese: I'm sure it's something that could be added, but given that there's an existing workaround that's both simple and 100% effective (without sacrificing any functionality), it's probably not likely that we'll be seeing anything akin to `TEntity<?>` any time soon ;)
Adam Robinson
Darnit. Fell on this while looking for a similar answer... Given that one can call "typeof(myGenericClass<>)", I was hoping that a constraint could be defined in a similarly open fashion. Nice answer.
Remi Despres-Smyth
A: 

If the Id types are important inside the Association definition, you could create an enclosing "context":

public static partial class EntityIds<TId1, TId2> {

    public class Association<TEntity1, TEntity2>
      where TEntity1 : Entity<TId1>
      where TEntity2 : Entity<TId2>
    {
      // ...
    }

}

This way, the Association class declaration is still intelligible, and it retains the necessary type arguments for its type parameters.

A factory method could help you with the normal case:

public static class AssociationFactory {
  public static EntityIds<TId1, TId2>.Association<Entity<TId1>, Entity<TId2>> Create<TId1, TId2>(/*params...*/) {
    return new EntityIds<TId1, TId2>.Association<Entity<TId1>, Entity<TId2>>(/*params...*/);
  }
}

It that looks like too much, and if you don't have entity specializations, you could model the association differently:

public class Association<TId1, TId2>
{
  // ... 
  Entity<TId1> Entity1 { get; set; }
  Entity<TId2> Entity2 { get; set; }
  // ...
}
Jordão