5

With linq i can create a query like this

XElement.Elements("...").Select(x=> useX(x));

now as x creates only a wrapper Action and useX's parameter is XElement you can use it like this aswell:

XElement.Elements("...").Select(useX);

However when i have a type that has a constructor with a matching type i.e. MyClass(XElement element) i have to use:

XElement.Elements("...").Select(x=> new MyClass(x));

My question: Is there any way to shorten the construction of an object in a way like above but with a constructor? I imagined something like this:

XElement.Elements("...").Select(MyClass);
ShinuSha
  • 73
  • 5
  • Your class might have different overloaded constructors, and presence of `x` as a lambda parameter is not enough for compiler to infer which ctor to use: for example, you might want to use default one of `MyClass`, regardless if there is `x` or not. – Tigran Jan 29 '18 at 14:43
  • You can have multiple overloads of a method too, so not really an argument @Tigran – Patrick Hofman Jan 29 '18 at 14:44
  • @PatrickHofman: not sure what multiple overloaded methods have to do with all of this. my point is that in this scenario you have to specify concrete ctor to use, even in case when compiler is able to some degree determine which ctor to use on its own. you have to be explicit. – Tigran Jan 29 '18 at 14:46
  • 1
    But how does `.Select(useX)` know which method to call? It is just a matter of method resolution, and constructors could go the same way @Tigran – Patrick Hofman Jan 29 '18 at 14:48
  • This isn't quite a duplicate of https://stackoverflow.com/questions/35420610/passing-a-method-to-a-linq-query, but the answer at https://stackoverflow.com/a/35422304/400547 explains why the answer to this is "no". – Jon Hanna Jan 29 '18 at 14:48
  • Incidentally, there are times where explicitly defining the action has a slight performance (in both time taken and memory used) advantage over passing in the method group, with current compiler implementations; the action will be cached in many cases, but the method group will not. – Jon Hanna Jan 29 '18 at 14:50

3 Answers3

9

Is there any way to shorten the construction of an object in a way like above but with a constructor

Short answer: No, there is not.

Longer "answer" (not actually an answer, more a workaround if you want it):

You can add a static construction method to MyClass:

public class MyClass
{
   public MyClass(XElement elem) 
   {
       // your constructor logic
   }

   public static MyClass Create(XElement elem)
   {
      return new MyClass(elem);
   }
}

and use that

XElement.Elements("...").Select(MyClass.Create);

But whether it's worth it is up to you! (Personal opinion: It's not worth it, just stick with new MyClass(x))

Jamiec
  • 133,658
  • 13
  • 134
  • 193
3

No, you can't shorten a call to a constructor inside a lambda expression. The problem is that a constructor is called from an operation with new new operator.

You are stuck with .Select(x=> new MyClass(x)). Of course, you can make a factory method to call instead, but that is more like a workaround.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
0

Actually the syntax that accepts a method-group only works, if the actually delegate to be used can clearly be inferred from the usage. E.g. a method returning an int and expecting one, that has no further overloads, can also be used like this:

Select(myMethod);

However if there are overloads, you can´t do this, as it´s unclear which of them you mean.

For constructors it´s a bit different. There´s no way on referencing it using a method-group. MyClass isn´t a valid method-group for new MyClass().

So in short: you can´t reference a constructor using a method-group.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111