Set only the second type of argument to the general method

I need to create a method to select the firts property from a collection with the specified type.

I created a method similar to this (I removed some parts for brevity):

public static IQueryable<TResult> SelectFirstPropertyWithType<T, TResult>(this IQueryable<T> source) { // Get the first property which has the TResult type var propertyName = typeof(T).GetProperties() .Where(x => x.PropertyType == typeof(TResult)) .Select(x => x.Name) .FirstOrDefault(); var parameter = Expression.Parameter(typeof(T)); var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult)); var expression = Expression.Lambda<Func<T, TResult>>(body, parameter); return source.Select(expression); } 

And I can call this method the following:

 List<Person> personList = new List<Person>(); // .. initialize personList personList.AsQueryable() .SelectFirstPropertyWithType<Person, int>() .ToList(); 

Everything is working fine.

But I do not want to set the first type of the argument as Person , because the compiler can infer this type of argument from the source of the collection. Is there a way to call the method as follows:

.SelectFirstPropertyWithType<int>()

The problem is that I need the T parameter inside my method, and I don't want to create Func with reflection at runtime.

Thanks.

+5
source share
2 answers

C # Generics simply does not allow you to specify a subset of type parameters. This is all or nothing.

A way around this is to write a free interface. You break this operation in a chain of methods.

  public class FirstPropertyWithTypeSelector<T> { private readonly IQueryable<T> _source; public FirstPropertyWithTypeSelector(IQueryable<T> source) { _source = source; } public IQueryable<TResult> OfType<TResult>() { // Get the first property which has the TResult type var propertyName = typeof(T).GetProperties() .Where(x => x.PropertyType == typeof(TResult)) .Select(x => x.Name) .FirstOrDefault(); var parameter = Expression.Parameter(typeof(T)); var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult)); var expression = Expression.Lambda<Func<T, TResult>>(body, parameter); return _source.Select(expression); } } public static FirstPropertyWithTypeSelector<T> SelectFirstProperty(this IQueryable<T> source) { return new FirstPropertyWithTypeSelector<T>(source); } 

Now you can call:

  personList.AsQueryable() .SelectFirstProperty().OfType<int>() .ToList(); 
+2
source

Not. The compiler should be able to output all type parameters. If he cannot require you to specify all of them.

The compiler cannot tell you that it can output the first or second, so instead of having a non-deterministic compilation application, it just breaks.

+3
source

All Articles