Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shorten this LINQ query via the help of an anonymous type?

I'm making a query on a MethodInfo[] where I'm trying to find all the methods that have a return type of void, and has only one parameter of a certain type. I want to do it in the most minimalistic and shortest way.

One way to do it would be:

var validMethods = methods.Where(m => m.ReturnType == typeof(void) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == wantedType);

or

var validMethods = methods
      .Where(m => m.ReturnType == typeof(void))
      .Where(m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == wantedType);

But there's a redundant GetParameters call - One call should be enough. So I thought I could cache that to an anonymous type like so:

var validMethods = methods
    .Where(m => m.ReturnType == typeof(void))
    .Select(m => new { Params = m.GetParameters() })
    .Where(p => p.Length == 1 && p[0].ParameterType == transition.eventType);

But it didn't work, I got errors saying there's no Length nor an indexer for the anonymous type p which is of type ParameterInfo[]

Is this the shortest way of writing this query? if so, how can I get the anonymous type to work? if not, what's the shortest way of doing this? (get all methods of void return, and of one param where that param is of a certain type)

Thanks for any help :)

like image 854
vexe Avatar asked Jan 03 '14 08:01

vexe


People also ask

What is anonymous type in linq?

Anonymous types typically are used in the select clause of a query expression to return a subset of the properties from each object in the source sequence. For more information about queries, see LINQ in C#. Anonymous types contain one or more public read-only properties.

Can you project a query to an anonymous type?

In some cases, you might want to project a query to a new type, but the query would be your only use for the new type. Rather than create the type, you can project to an anonymous type.


2 Answers

With query syntax you can introduce new range variable which will hold method parameters

from m methods.Where(m => m.ReturnType == typeof(void))
let p = m.GetParameters()
where p.Length == 1 && p[0].ParameterType == wantedType
select m

Method syntax is not that beautiful:

methods.Where(m => m.ReturnType == typeof(void))
       .Select(m => new { m, p = m.GetParameters() })
       .Where(x => x.p.Length == 1 && x.p[0].ParameterType == wantedType)
       .Select(x => x.m);
like image 167
Sergey Berezovskiy Avatar answered Sep 30 '22 10:09

Sergey Berezovskiy


I agree with Sergey Berezovskiy that the method syntax he showed is less beautifull than the query syntax. But the method syntax can be rewritten to this:

methods.Where(IsTheRightMethod);

and a regular method:

private bool IsTheRightMethod(MethodInfo methodInfo)
{
    if (methodInfo.ReturnType != typeof(void)) return false;
    var parameters = methodInfo.GetParameters();
    return parameters.Length == 1 && parameters[0].ParameterType == typeof(wantedType);
}

The OP wanted a short solution. If this is short depends on how you look at it. The Linq query is shorter and anonymous types are not created.

This solution also makes debugging easier and is also easier to extend. An example of the latter might be:

methods.Where(m => IsTheRightMethod(m, typeof(wantedType), 1));

and

private bool IsTheRightMethod(MethodInfo methodInfo, Type parametertype, int parametersLenght)
{
    if (methodInfo.ReturnType != typeof(void)) return false;
    var parameters = methodInfo.GetParameters();
    return parameters.Length == parametersLenght && 
           parameters.All(p => p.ParameterType == parametertype);
}
like image 34
Alex Siepman Avatar answered Sep 30 '22 08:09

Alex Siepman