C # generic method with interface type constraint

Suppose I have:

  • General method Get<T>

  • Multiple interfaces IEntity

    ,IValue

  • Several classes that respectively implement these interfaces ex: Entity

    IEntity

    , Value

    IValue

    etc.

=> Is there a way for a method Get<T>

to only allow interfaces as generic types?

Get<IEntity>(42); //Allowed
Get<Entity>(42);  //Compiler error

      

My current solution looks like this:

  • A generic Get<T>

    type constrained method where T: IPersistable

    (to prevent most types from being passed as a parameter)
  • Interfaces implement IPersistable

The function actively checks the type:

public T Get<T>(long id) where T : IPersistable
{
   if (typeof (T) == typeof (IEntity))
      return (T) EntityDao.Get(id);
   if (typeof (T) == typeof (IValue))
      return (T) ValueDao.Get(id);

   //...

   throw new TechnicalException("Type not supported");
}

      

=> The problem is this:

  • It's not clean ... I could live with this because there are only very few types to check from
  • The signature does not match the function's action. It allows IPersistable

    in, but not really <- , which really worries me :(

Edit: I am considering such restrictions to avoid overpopulating my class.

I have something like 8 or 9 generic methods in this class that all work so well. An intuitive way to work would be like @DanielHilgarth suggested using only one method per type. Currently, methods can only be called with 4 or 5 types. But still, this will mean 32-40 methods in this class.

If possible, I would like to avoid this.

Edit2: The need to prevent "real" classes from being called occurs due to a covariance / contravariance issue. The EntityDao and ValueDao methods Get<T>

return objects IEntity

and IValue

. What works great when I query for a single object fails when I call the collection in methods GetAll<T>

as I cannot use IEnumerable<IValue>

in IEnumerable<Value>

.

I just noticed this answer from @JonSkeets about list casting. This could be a workaround ...

+3


source to share


2 answers


You just have to create custom methods. Sample code c if

shows that your current method does nothing. These are several.

Just go with:

GetEntity(42);
GetValue(13);

public IEntity GetEntity(long id)
{
    return EntityDao.Get(id);
}

public IValue GetValue(long id)
{
    return ValueDao.Get(id);
}

      



This is much cleaner on all layers:

  • GetEntity

    vs. Get<IEntity>

  • You communicate clearly what is possible. You have no runtime exceptions.
  • Your get methods don't require type switching.

If that leads to too many similar methods in your service, it's time to rip out new classes, for example. one for Entity

and one for Value

. Then you can provide your own service properties that return new classes. I do the same when implementing my request objects . It might look like this: service.Values.Get(13)

andservice.Entities.Get(42)

+5


source


This could be an alternative:

abstract class Persistable<T>
{
    protected static Func<long, T> mapFunction;
    public static T Get(long id)
    {
        return mapFunction(id);
    }
}

class Entity : Persistable<Entity>
{
    public static Entity()
    {
        Persistable<Entity>.mapFunction = input => EntityDao.Get(input);
    }
}
class Value : Persistable<Value>
{
    public static Value()
    {
        Persistable<Value>.mapFunction = input => ValueDao.Get(input);
    }
}

      



Your method Get

will look something like this:

public T Get<T>(long id) // maybe you restrict the T to something
{
    Persistable<T>.Get(id);
}

      

+1


source







All Articles