Вопрос

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.

Другие советы

Not sure I got right your question, just a wild guess, would this work for you?:

IQueryable<Entity<TId>> Query<TId>();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top