This is a follow-up to another question where I received a lot of great comments and answers. That question brought up this one.
Say I have the following abstract class:
public abstract class Entity<TId> : IEquatable<Entity<TId>>
{
public TId Id { get; protected set; }
// plus implementation of IEquatable, GetHashCode override, etc.
}
The other question I asked had to do with how to implement an interface for entity commands, which now looks like this:
public interface ICommandEntities
{
void Create<TId>(Entity<TId> entity);
void Update<TId>(Entity<TId> entity);
void Delete<TId>(Entity<TId> entity);
void Reload<TId>(Entity<TId> entity);
}
Before, I was trying to figure out how to do this with generic type constraints to restrict the method arguments to be of type Entity<TId>
. Answers to the previous question told me I don't need to do that, I can just use my abstract class as the method argument.
However, I still don't understand how can I do the following, where the interface method has no arguments?
public interface IQueryEntities
{
IQueryable<TEntity> Query<TEntity>() where TEntity : ???????;
}
When Invoking this method, I only want to pass a single generic argument like so:
var queryable1 = queries.Query<EntityAbc>();
var queryable2 = queries.Query<EntityXyz>();
... where the entity classes might look something like this:
public class EntityAbc : Entity<string> {...}
public class EntityXyz : Entity<int> {...}
How can I constrain the interface method so that it only allows classes that extend from Entity<TId>
to be passed as a generic argument?
Change your interface to be generic:
public interface IQueryEntities<TId>
{
IQueryable<TEntity> Query<TEntity>() where TEntity : Entity<TId>;
}
and then when you implement it:
public class EntityAbc : Entity<string>, IQueryEntities<string>
or maybe event his:
public abstract class Entity<TId> : IEquatable<Entity<TId>>, IQueryEntities<TId>
So to update to reflect the comments. Making that interface generic is still the approach. If you didn't want the entities implementing the interface, no problem, you could do this:
public class QueryEntities<TId> : IQueryEntities<TId>
{
public IQueryable<TEntity> Query<TEntity>()
where TEntity : Entity<TId>
{
...
}
}
Using that might look like this:
var queries = new QueryEntities<string>();
queries.Query<EntityAbc>();
But, you're not going to be able to send any entity into that interface unless you make the method itself receive the TIn
. If you were to make the method itself generic like that the code would be this of course:
var queries = new QueryEntities();
queries.Query<EntityAbc, string>();
the interface for that looks like this:
public interface IQueryEntities
{
IQueryable<TEntity> Query<TEntity, TId>() where TEntity : Entity<TId>;
}
but you don't want that.