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:
public class XYZ
{
public static XYZ Action<T, TKey> (TKey key, T element)
{
return new XYZ<T>(element);
}
}
EDIT: Responding to the question edit.
No, you can't do something like this:
abc.Accept(Ordering.By(u => u.Id));
The problem is the inner expression:
Ordering.By(u => u.Id)
What's the type of u
here? It could be any class with an Id
property. Note that the C# compiler will need to work out the type of this expression before it looks at abc.Accept
. Even if abc.Accept
only worked for an Ordering<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:
Ordering<User>.By(u => u.Id)
Use a generic method in a non-generic class, specifying both type arguments explicitly:
Ordering.By<User, string>(u => u.Id)
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:
Ordering.By((User u) => u.Id)
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:
public static Ordering<T> By<T,TKey>(Expression<Func<T, TKey>> func, T example)
{
return By<T, TKey>(func);
}
...
Ordering.By(u => u.Id, dummyUser);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.