Given the following two classes:
public class ABC
{
public void Accept(Ordering<User> xyz)
{
// Do stuff with xyz...
}
}
public class Ordering<TEntity>
where TEntity : class
{
private readonly Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> Transform;
private Ordering(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> transform)
{
this.Transform = transform;
}
public static Ordering<TEntity> By<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => query.OrderBy(expression));
}
public static Ordering<TEntity> ByDescending<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => query.OrderByDescending(expression));
}
public Ordering<TEntity> ThenBy<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => this.Transform(query).ThenBy(expression));
}
public Ordering<TEntity> ThenByDescending<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => this.Transform(query).ThenByDescending(expression));
}
public IOrderedQueryable<TEntity> Apply(IQueryable<TEntity> query)
{
return Transform(query);
}
}
Used in the following way:
ABC abc = new ABC();
abc.Accept(Ordering<User>.By(u => u.Id));
Is there any way to infer the type of T like so:
abc.Accept(Ordering.By(u => u.Id));
You can do it, but not in a generic type. Generic type inference like this only occurs for generic methods. Declare a separate non-generic type, with a generic method:
EDIT: Responding to the question edit.
No, you can’t do something like this:
The problem is the inner expression:
What’s the type of
uhere? It could be any class with anIdproperty. Note that the C# compiler will need to work out the type of this expression before it looks atabc.Accept. Even ifabc.Acceptonly worked for anOrdering<User>, it would fail.There are three options here:
Use a static method in the generic class, specifying the source type argument explicitly, and inferring the key type argument:
Use a generic method in a non-generic class, specifying both type arguments explicitly:
Use a generic method in a non-generic class, specifying the type of the lambda parameter explicitly, and letting the compiler infer the key type argument:
Obviously, all of these cases require you to specify the type explicitly somewhere.
One other option which is a little bit weird is relevant if you’ve typically already got an instance of
User(or at least a variable of that type). You can use that as a sort of example, which gets ignored: