Home > Mobile >  Use IsAssignableTo with open generic interfaces
Use IsAssignableTo with open generic interfaces

Time:10-25

I'm trying to get all the interfaces (they are all open generic) derived from IService that a Random class implements. I'm sure that at least one interface Random is implementing inherits from IService<,> but no items is being added to the iServiceTypeInterfaces list.

I have the following code:

var iServiceTypeInterfaces = new List<Type>();
Type iServiceGeneric = typeof(IService<,>);
foreach(Type i of Random.GetInterfaces())
{
  Type currentGenericType = i.GetGenericTypeDefinition();
  bool isAssignable = currentGenericType.IsAssignableTo(iServiceGeneric);
  if(isAssignable)
  {
    iServiceTypeInterfaces.Add(i);
  }
}
public interface IService<T, TSearcheable>
  where T : class
  where TSearcheable : class
{
  Task<IEnumerable<T>> GetAll(TSearcheable searchObj);

  Task<T> GetById(Guid id);

  Task Create(T entity);

  Task Update(T entity);

  Task Delete(T entity);
}
public interface IProjectService<T, TSearcheable> : IService<T, TSearcheable>
  where T : class
  where TSearcheable : class
{
  Task<List<Technology>> GetTechs(List<Guid> ids);
}

CodePudding user response:

IsAssignableTo isn't designed to return true for the open type IProjectService<,> and the open type IService<,>. After all, IProjectService<T, U> is not assignable to IService<V, W>, where T, U, V, W are any type. Yes, that is the question you are asking - you are not asking whether IProjectService<T, U> is assignable to IService<T, U> (which it is), because both types are open types! There's no information about their type arguments at all.

I'd recommend just writing out the logic you want using LINQ. From the interfaces of Random, you want the generic interfaces:

  • whose generic definition is the same as IService<,>, or
  • whose list of super interface contain a generic definition that is IService<,>

The LINQ is straightforward:

static List<Type> GetAllInterfacesAssignableTo(Type interfaceType, Type targetType) {
    var genericInterface = interfaceType.GetGenericTypeDefinition();
    return targetType.GetInterfaces()
        .Where(x => x.IsGenericType)
        .Where(x =>
            x.GetGenericTypeDefinition() == genericInterface ||
            x.GetInterfaces().Select(i => i.GetGenericTypeDefinition()).Contains(genericInterface)
        )
        .ToList();
}

Usage:

GetAllInterfacesAssignableTo(typeof(Service<>), typeof(Random))

CodePudding user response:

I ended up not using the afforementioned method IsAssignableTo and accesing all inherited interfaces from each one.

var iServiceTypeInterfaces = new List<Type>();
Type iServiceGeneric = typeof(IService<,>);
foreach(Type i of Random.GetInterfaces())
{
  IEnumerable<Type> inheritedInterfaces = i.GetInterfaces().Select(i => i.GetGenericTypeDefinition())
  bool inheritsFromIService = inheritedInterfaces.Contains(iServiceGeneric);
  bool isIService = i.GetGenericTypeDefinition() == iServiceGeneric;
  if(inheritsFromIService || isIService)
  {
    iServiceTypeInterfaces.Add(i);
  }
}
  • Related