I'm trying to call String.Format from with in a Linq.Expression tree. Here's a quick example:
var format = Expression.Constant("({0}) {1}");
var company = Expression.Property(input, membernames.First());
var project = Expression.Property(input, membernames.Last());
var args = new Expression[] {format, company, project};
var invoke = Expression.Call(method,args);
The issue however is that String.Format has the signature of:
String.Format(string format, params object[] args)
and I'm trying to pass in Expression[].
Now I could go through all the trouble of creating an array, populating it with the results of my expressions, but what I really want the result to be, is something like this:
String.Format("({0}) {1}", input.foo, input.bar)
How do I go about calling a params function via Linq Expressions?
What params actually does is just to specify ParamArrayAttribute for that parameter. The C# compiler understands this, and creates the array behind the scenes.
Expressions don't understand this, so you actually have to create the array by yourself, if you want to call a method with params. This can be also seen by the fact that when you assign a lambda using params-method to an expression, the expression contains the array creation:
Expression<Func<string>> expression = () => string.Format("",1,2,3,4);
string expressionString = expression.ToString();
Here, expressionString will contain this string:
() => Format("", new [] {Convert(1), Convert(2), Convert(3), Convert(4)})
To create an expression that creates an array, use the Expression.NewArrayInit() method.
That being said, if you only want two parameters (or one or three), there is an overload of string.Format() that you can use directly from an expression.
params is just syntactic sugar. Ultimately the parameter is just an array. Therefore, the parameter type should be object[] and an expression describing such an array is what you should pass as the second argument. In other words, you should only have two arguments, not three. And the second argument should be a two-element array containing what is currently your 2nd and 3rd arguments.
Related
I found a little script that I understand fully. I've got a string with "1 -2 5 40" for example. It reads the input string, splits it into a temporary array. Then this array is parsed and each element is transformed into an integer. The whole thing is order to give the nearest integer to zero.
But what I don't understand is the notation Select(int.Parse). There is no lambda expression here and the method int.Parse isn't called with brackets. Same with the OrderBy(Math.Abs)
Thank you in advance =)
var temps = Console.ReadLine().Split(new []{' '}, StringSplitOptions.RemoveEmptyEntries);
var result = temps.Select(int.Parse)
.OrderBy(Math.Abs)
.ThenByDescending(x => x)
.FirstOrDefault();
int.Parse is a method group - what you're seeing is a method group conversion to a delegate. To see it without LINQ:
Func<string, int> parser = int.Parse;
int x = parser("10"); // x=10
It's mostly equivalent to:
Func<string, int> parser = text => int.Parse(text);
... although there are plenty of differences if you want to go into the details :)
Select(int.Parse) is nearly equivalent to Select(x => int.Parse(x)).
The Select demands an Func<T, R>, which in this case is also the signature of int.Parse (it has a single parameter with a return value). It convers the method group to the matching delegate.
In this case Func<T, R> will map to Func<string, int>, so it matches the int Parse(string) signature.
int.Parse is a method with signature string -> int (or actually, a method group, with different signatures. But the compiler can infer you need this one, because it is the only one that fits.
You could use this method as a parameter wherever you would supply a delegate parameter with the same signature.
The parameter for .Select() is Func<T1, T2>() where T1 is the input parameter (the individual values of temps), and T2 is the return type.
Typically, this is written as a lambda function: x => return x + 1, etc. However, any method that fits the generic definitions can be used without having to be written as a lambda since the method name is the same as assigning the lambda to a variable.
So Func<string, int> parseInt = s => Convert.ToInt32(s); is syntactically equivalent to calling the method int.Parse(s).
The language creates the shortcut of automatically passing the Func parameter to the inside method to create more readable code.
Select LINQ IEnumerable<> extension method signature looks like that:
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector
)
Look at the selector argument. In your case you pass to Select .Net standard function int.Parse which has signature:
public static int Parse(
string s
)
.Net compiler can convert delegates to Func<...> or Action<...>. In case of int.Parse it can be converted to Func and therefore can be passed as argument to Select method.
Exactly the same with OrderBy. Look at its signature too.
This question already has answers here:
Calling a function using reflection that has a "params" parameter (MethodBase)
(3 answers)
Closed 8 years ago.
Trying to invoke a method with an arbitrary number of parameters:
Type objType = obj.GetType();
MethodInfo method = objType.GetMethod("InvokedMethod");
method.Invoke(obj, new string[] { "param1", "param2" });
The method signature looks like that:
public void InvokedMethod(params string[] args) { ... }
Why I get following Exception:
System.Reflection.TargetParameterCountException (Parameter count mismatch)
The method doesn't accept two parameters, it accepts one parameter that is an array. The compiler will perform a transformation such that a method call of two strings will be transformed into a call of a single array with two values. That transformation won't be done for you when using reflection. You'll need to explicitly create an array and put the two values in it:
method.Invoke(obj, new object[] { new[]{"param1", "param2"} });
Remember that Invoke doesn't accept a single value of that one parameter either. It accepts an array of all parameters. Passing new string[] { "param1", "param2" } to Invoke is telling Invoke that you have two parameters, each of which are strings. You need to wrap your one array parameter in another array so that Invoke sees that you have one parameter that is itself an array.
Try this:
method.Invoke(obj, new object[] {new string[] {"param1", "param2"}});
.Invoke takes an array of arguments that represents the entire signature. in your case the first argument should be an array of strings. So you have to pass in an array of objects with the first element being the array of strings.
Background:
I am creating a COM library and would like to use a modified version of code from this answer. I would like to pass an object to WhatsMyName COM function and return a string representation. I am not entirely sure this is yet possible but trying doesn't hurt ;)
This is how I am seeing it:
Dim myComInst as new MyComLib
MsgBox myComInst.WhatsMyName(myComInst)
and expecting myComInst to be returned.
I am stuck at wrapping the below function so it doesn't take an expression but an object parameter.
public static class MemberInfoGetting
{
public static string GetMemberName<T>(Expression<Func<T>> memberExpression)
{
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
return expressionBody.Member.Name;
}
}
And I can use it like this
string testVariable = "value";
string nameOfTestVariable = MemberInfoGetting.GetMemberName(() => testVariable);
which is rather straight forward.
What I am trying to do is to create a wrapper around it so I can pass any object instead of using the lambda expression in the parameter.
So instead of () => testVariable I'd like to pass just any object.
I have tried to wrap it like this
public string WhatsMyName(object objInstance)
{
return MemberInfoGetting.GetMemberName(() => objInstance);
}
but it returns objInstance instead of the object I am passing to the function.
I have tried to use (forgive me) a ref keyword but it doesn't work with lambda expressions.
If any one can first verify whether what I am trying is possible or not that would be great! If it is, then please guide me or point to references about writing a wrapper function for a lambda expression.
You time and help highly appreciated!
If you pass in the actual expression, rather than an Expression object that represents it, then the expression is being evaluated to its value before it is passed to the function. By the time you're inside the function it is too late to access that information. Using an Expression is passing all of the information used to represent that expression, rather than just its value, which is why you can access it from inside of that function.
Can you say what is the use of the ()=> and =>? I saw this in a code. I did not get any reference for this.
this.Dispatcher.BeginInvoke(()=>
{
//some thing..
};
=> is the lambda operator in C# and is read as "goes to". A lambda expression is an anonymous function and can be used to create a delegate.
Your example takes no arguments as indicated by the empty parens preceding the lambda operator. A lambda expression with one argument might look like this:
n => n.toString()
That expression would return the string representation of n, when invoked. A lambda expression can have multiple arguments as well, contained in parentheses:
(n, f) => n.toString(f)
A common use would be in a Func<T>:
Func<int, string> getString = n => n.toString();
int num = 7;
string numString = getString(num);
This is, of course, a silly example, but hopefully helps to illustrate its use.
This notation is that of a lambda expression which takes no argument. If the lambda expression made use of arguments they would be declared in the empty set of parenthesis as in say...
this.Dispatcher.BeginInvoke((x, y) => { do some' with x and/or y }, 12, somevar);
In a nutshell, lambda expressions allows creating "nameless" functions, right where they are needed.
In the example of the question, the BeginInvoke() method requires its first parameter to be a delegate (a "pointer to a method"), which is exactly what this lambda expression provides.
It's a lambda expression that has no parameters.
Check out this page http://codebetter.com/karlseguin/2008/11/27/back-to-basics-delegates-anonymous-methods-and-lambda-expressions/
If you don’t have any parameters, like in our example, you use empty
paranthesis:
() => {…}
In JavaScript I can assign a value to a variable by dynamically creating a function. Such as
var name = (function () { name="bob"; return name; }());
I'm fairly certain that with C# 4.0 the same type of thing is possible. Could someone show me the syntax of how the same line above would look in C#?
Also, if you could jog my memory on what the proper term for creating this type of dynamic function is, it would be much appreciated!
Thanks for your help!
PS: It's likely this question has been asked before, but since I was unclear on the nomenclature I may have missed finding it. If that's the case, I apologize!
You can use anonymous methods:
Func<string> anonymousFunction = () => { string name = "bob"; return name; };
string myName = anonymousFunction();
The syntax on the first line is a lambda, which is the C#3.0 and above way of declaring anonymous methods. The above function takes no arguments, but there's nothing stopping you from including them as well:
Func<string, string> makeUppercase = x => x.ToUpper();
string upperCase = makeUppercase("lowercase");
Note that since there is only one parameter, you can elide the brackets around it. As well, since the entire method is a single return statement, you can elide both the brace brackets as well as the return statement itself.
This type of lambda is very common when using the LINQ extension methods, since many of them require a single-argument method that returns a value:
var numbers = new List<int>() { 1, 2, 3, 4 };
var divisibleByTwo = numbers.Where(num => num % 2 == 0);
To answer your actual question, that syntax is not valid in C#. If you try this:
string output = (x => x.ToUpper())("lowercase");
You'll get an error message saying "Method name expected." You have to assign the anonymous method to a delegate first.
Generally what you want to look into are Func/Actions:
http://msdn.microsoft.com/en-us/library/bb549151.aspx
http://msdn.microsoft.com/en-us/library/018hxwa8.aspx
And for that matter, lambda expressions:
http://msdn.microsoft.com/en-us/library/bb397687.aspx