In the code from this link: http://c-sharp-programming.blogspot.com/2008/07/cross-thread-operation-not-valid.html, a delegate is used to update a text box's value from a worker thread.
I can basically see what's happening, but the syntax of this line specifically:
label1.Invoke(del, new object[] { newText });
is confusing to me. Can someone explain it please? Why do we use a new object array syntax for the delegate when there's only one parameter?
Full code:
delegate void updateLabelTextDelegate(string newText);
private void updateLabelText(string newText)
{
if (label1.InvokeRequired)
{
// this is worker thread
updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
label1.Invoke(del, new object[] { newText });
}
else
{
// this is UI thread
label1.Text = newText;
}
}
TL;DR:
Control.Invoke is calling DynamicInvoke on your delegate which takes an object array of parameters to work with any delegate type.
//
The keyword delegate in C# in analagous to specifying a type of function pointer. You can use that type to pass methods of a specific signature. In your example, the signature is for a method that takes 1 arg (a string) and returns nothing (void). The method updateLabelText matches that sig. The line:
updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
Is just a full-text way of saying:
updateLabelTextDelegate del = updateLabelText;
Then, you can pass your variable del, which is now a pointer to the method updateLabelText to the Control.Invoke method.
label1.Invoke(del, new object[] { newText });
Which thanks to params being using in the Control.Invoke signature, you don't even have to explicitly say it's an object[]
label1.Invoke(del, newText);
The Invoke takes an array of objects, which it'll use as the args to the delegate given. (Yes your update method takes one string arg, keep reading) With your variable del, you could call updateLabelText yourself:
del(newText);
Which would essentially be the same as:
updateLabelText(newText);
Inside Control.Invoke, they are calling your del method, but it doesn't have to know how many args it takes thanks to some helper methods on delegates. You would find something like this:
EDIT I did some deep digging for science, the invocation internally is more like:
del.DynamicInvoke(args);
Where args is an object[]. For more info on things you can do with your delegate variable (which is of type Delegate), read more here.
If you look at the method signature of Control.Invoke, you'll see it takes params Object[] args. You can either pass object[] args or a single argument.
The object array is passed to the delegate's Invoke method. In this case updateLabelTextDelegate takes a single string parameter, hence the single element in the array.
In fact the array does not need to be explicitly created, and
label1.Invoke(del, newText)
is also valid.
First, it's worth noting that this isn't calling Invoke on the delegate - it's calling Invoke on the control. Now if you look at the signature of Control.Invoke being used here, it's this:
public Object Invoke(
Delegate method,
params Object[] args
)
If the method took one specific delegate type, it could take the appropriate parameter types for that delegate. In your case your delegate only takes one parameter, but suppose we wanted to pass in an Action<string, string, int> - using the very general approach above, we can do that with:
control.Invoke(someDelegate, new object[] { "foo", "bar", 10 });
So the answer is that the object[] is there to provide generality, because the delegate type is left general too. It's a bit like MethodInfo.Invoke - without knowing at compile-time how many parameters there are, a value of type object[] is the best way of allowing various situations.
Related
I want to write a function that takes a function as an argument and then do different things based on whether the passed-in function returns void vs a value.
C# signature checking can't tell the difference so I'm stuck doing it in code.
Is there an easy way to test whether an arbitrary function returns void?
To be clear. I explicitly am not interested in a compile error. I just want the equivalent of what I can do for any other object.
void IsString(object o) => o is string;
void ElseWhere() {
object o = 1;
if (IsString(o)) Bla();
However even this gets a compile error claiming the two methods are ambiguous. It doesn't flag the methods themselves ambiguous but I get an error on the call saying it can't resolve between them.
private static bool HasNoReturnValue(Action o) => true;
private static bool HasNoReturnValue(Func<object> o) => false;
...
if (HasNoReturnValue(SomeFunction)) Bla();
As do anything I've tried involving typeof:
if (SomeFunction is typeof(Func(object>)) Bla();
Let's say you have two methods, one of which returns a Boolean and one which returns void.
void SomeFunction1()
{
}
bool SomeFunction2()
{
return false;
}
To pass either of these as a pointer to a method, you have to convert them to a delegate. Two types of delegates: Action and Func<bool>, respectively:
var action1 = new Action(SomeFunction1);
var action2 = new Func<bool>(SomeFunction2);
You can then write two methods that accept these types as arguments:
void AcceptDelegate(Action action)
{
Console.WriteLine("The delegate returns void.");
}
void AcceptDelegate(Func<bool> func)
{
Console.WriteLine("The delegate returns a Boolean.");
}
And call them like this:
AcceptDelegate(action1);
AcceptDelegate(action2);
Or you could pass the method group directly and the compiler will figure out the type (Why? See the Microsoft documentation on c# method group conversions):
AcceptDelegate(SomeFunction1);
AcceptDelegate(SomeFunction2);
Either way you call them, you would get this output:
The delegate returns void.
The delegate returns a Boolean.
The reason this works is the compiler will automatically pick the right one at compile-time, based on the type of the delegate, just as it would pick the overload for any type such as string or integer. This is the type-safe / early-bound way to do it.
If you insist on an "any delegate"/ late binding sort of approach, you could do something like this:
void AcceptAnyDelegate(Delegate anyAction)
{
Console.WriteLine("The function returns a {0}", anyAction.Method.ReturnType);
}
Because the signature isn't type specific, you have to pass the specific delegates this time (Why? See this answer):
AcceptAnyDelegate(action1);
AcceptAnyDelegate(action2);
And the output would be:
The function returns a Void
The function returns a Boolean
Edit
After rereading your comments, I believe the confusion here is due to a misunderstanding of method groups and delegates.
When you write something like this:
Foo(Bar);
...it appears you believe you are passing to Foo a direct reference to the Bar method. That is not correct. What you are doing is specifying a method group, which the compiler can then use to infer the type of delegate to pass. If Bar is a method with no inputs or outputs, the above code is exactly the same as
Foo(new Action( Bar ));
...only the creation of the delegate is hidden from you by the compiler.
All delegates are specifically typed with respect to their parameters and return type. The Delegate base type is abstract and cannot exist in concrete form. So there is no such thing as passing a type-agnostic function reference-- it doesn't exist in c#.
If you really really want to pass something that is type-agnostic, you can ask the caller to pass a lambda expression:
Foo( () => SomeFunction1() );
You could then parse the expression to figure out the method's inputs and outputs:
void Foo(Expression<Action> anyAction)
{
var mce = anyAction.Body as MethodCallExpression;
var method = mce.Method;
Console.WriteLine("The method has a return type of {0}", method.ReturnType.Name);
}
Then to invoke the expression you would use:
var compiled = anyAction.Compile();
compiled();
That is the closest you're going to get.
There's two different types here:
Action for no return type
and
Func for a return type
Can you make two different signatures for these two different argument types?
This will do the trick
public static void TakeInAFunc<T>(T aFuncOrAction)
{
if (typeof(T) == typeof(Func<>))
{
// some value returned.
}
else if (typeof(T) == typeof(Action<>))
{
// it returns void.
}
}
Action<int, string> s = new Action<int, string>(delegate(int a,string b){});
Action<int, string> ss = delegate(int a, string b) { };
Why these both work? Why the constructor Action can accept both function and
delegator?
You're not really making a constructor call in the normal way, even though that's what it looks like.
Instead, this is a delegate-creation-expression as described in the C# 5 specification, section 7.6.10.5:
A delegate-creation-expression is used to create a new instance of a delegate-type.
delegate-creation-expression:
new delegate-type ( expression )
The argument of a delegate creation expression must be a method group, an anonymous function or a value of either the compile time type dynamic or a delegate-type.
It's almost always simpler to use the implicit conversion from an anonymous function (lambda expression or anonymous method) to a compatible delegate type, which is what your second line does.
If you remember back to C# 1, this was how we had to create delegate instances, although using method groups:
Action action = new Action(SomeMethod);
C# 2 introduced anonymous methods and also the implicit conversion from method groups to delegates:
Action action = SomeMethod;
These days, delegate creation expressions are relatively rare because there are more compact ways of doing the same thing.
Note that in some cases - if you're passing the anonymous function or method group as an argument for a parameter of type Delegate, for example - you can just cast instead of using a delegate creation expression:
Foo((Action<int, string>) delegate(int a, string b) {});
In the first line you explicitly create the Action<int, string> delegate to the anonnymous method. In the second - implicitly.
This is the code I use:
Type type = /* retrieved Type */
object arg = /* something that evaluates to null */
MyClass obj = (MyClass)Activator.CreateInstance(type, arg);
I get a crash, that given constructor doesn't exist on type type.
However, when I put this in Watch in Visual Studio 2008:
(MyClass)System.Activator.CreateInstance(type, null)
it creates the object as usual.
I even tried replacing my code with the one I put in the Watch. It works - object gets created.
My question: what's up with that?
Edit: MyClass doesn't have any constructors - apart from pregenerated parameterless constructor.
Edit 2: Using new object[0] instead of null still causes the same exception.
Your code is using the following overload of the Activator.CreateInstance Method:
public static Object CreateInstance(
Type type,
params Object[] args
)
Notice the params keyword.
Now let's take a look at your code:
Activator.CreateInstance(type, null)
This passes a null reference as args. In this case, the method looks for a parameter-less constructor.
object arg = // ...
Activator.CreateInstance(type, arg)
This passes a one-element array containing a null reference as args, because arg is declared as object. In this case, the method looks for a constructor with one parameter.
To avoid any ambiguity, call the method as follows:
object[] args = null; // 0 parameters
// - or -
object[] args = new object[] { "Hello World" }; // 1 parameter
var result = (MyClass)Activator.CreateInstance(type, args);
You've run into an issue with the params keyword.
The actual signature of the function is CreateInstance(Type, object[]). However, the fact that the object[] parameter is declared as params means that you can pass a variable number of arguments to the function and those arguments will get rolled into a new array, or you can directly pass an object array.
When the compiler performs overload resolution on the version where you pass null directly into the function, it does not convert the parameter into an array since null is a valid value for this. However, when you pass in a null-valued object variable, overload resolution has to turn that into an object array. This means that you are passing an object array with one value, which is null. The runtime then looks for a constructor with one argument, which it would then pass null to.
This is why the resolution fails at runtime.
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.
I'm having trouble emitting a call to a delegate whose type is unfinished at the time of the emit. I'll elaborate: I've declared the following delegate type:
// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open
// instance method: the implicit argument is here given explicitly, in
// 'firstArgument'. (See link below for explanation on open instance delegates).
public delegate Object DirectReadAccessor<T>(T firstArgument);
And now I'm trying to dynamically (i.e., with a TypeBuilder) create the following class:
public MyClass {
// Array of delegates. T has been replaced with MyClass because the
// argument will be 'this', which is of type MyClass.
private static DirectReadAccessor<MyClass>[] directReadAccessors;
// Method that looks up a delegate in the array of delegates and calls it
// with 'this'.
public Object DirectRead(int i) {
directReadAccessors[i](this);
}
// Method that is called by the declaring type to pass an array with the
// MethodInfo of some methods. MyClass then creates delegates for these
// methods and stores them in the directReadAccessors array.
public static void InitializeClass(MethodInfo[] directReadAccessorsMInfo) {
int length = directReadAccessorsMInfo.Length;
Type[] typeArguments = new Type[] { typeof(MyClass) };
directReadAccessors = new DirectReadAccessor<MyClass>[length];
// For each method in directReadAccessorsMInfo...
for (int i = 0; i < length; i++) {
// Create a delegate and store it in directReadAccessors.
directReadAccessors[i] = (DirectReadAccessor<MyClass>)
Delegate.CreateDelegate(
DirectReadAccessor<MyClass>, // Type of the delegate.
null, // Specify null first argument so that it's
// *open* instance.
directReadAccessorsMInfo[i].MakeGenericMethod(typeArguments) // The method.
);
}
}
}
*on open instance delegates.
This has been tricky because MyClass doesn't exist when I'm trying to declare the field directReadAccessors, which is of type DirectReadAccessor[], or when I emit the method InitalizeClass, which again uses MyClass, that doesn't exist yet (that's what I'm creating). However, I've managed to do all this, but now I'm having trouble with method DirectRead, since I don't know how to call the delegate once I have it on the stack. Apparently what I need is the following emit:
ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);
where invokeMInfo is the method Invoke on DirectReadAccessor, and which I should obtain like so:
MethodInfo invokeMInfo = typeof(DirectReadAccessor<MyClass>).GetMethod(
"Invoke", // Name of the method.
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, // Binding attributes.
null, // Binder.
new Type[] { typeof(MyClass) }, // Types of the arguments.
null // Modifiers for the arguments.
);
Again, the problem is that neither MyClass nor DirectReadAccessor exist yet. I have the TypeBuilder for MyClass and the unfinished DirectReadAccessor type, which I've created like this:
directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);
But if I try to call GetMethod("Invoke", ....) on directReadAccessorType as shown above I get a NotSupportedException, because I cannot obtain the method Invoke for an unfinished type. I've tested this assumption by making the same call after finalizing the type with:
typeBuilder.CreateType();
And indeed I do not get the exception in that case. However, I need to be able to get the Invoke method's MethodInfo before finalizing the type, while I'm emitting the code for InitializeClass.
It's a strange situation: I'll have the delegate when I need it, but I cannot produce the code to invoke it. Can anyone offer any help?
Thanks so much, and sorry for the lengthy post.
That's a tricky problem. I think that you should be able to use TypeBuilder.GetMethod to get the MethodInfo you need, using a call along the lines of
TypeBuilder.GetMethod(directReadAccessorType,
typeof(DirectReadAccessor<>).GetMethod("Invoke"));
Have you tried to compile the generic code and look at it using ILDASM ? It should show you the correct IL and hopefully the right emit to generate.
Would it make sense to minimize the amount of code in the generated class ?
By that, I mean that the generated class could implement an interface that gives access to its data. Through it, you could implement additional features that could be coded in C# instead of IL.