I'm having problems trying to create a thread with a ParameterizedThreadStart. Here's the code I have now:
public class MyClass
{
public static void Foo(int x)
{
ParameterizedThreadStart p = new ParameterizedThreadStart(Bar); // no overload for Bar matches delegate ParameterizedThreadStart
Thread myThread = new Thread(p);
myThread.Start(x);
}
private static void Bar(int x)
{
// do work
}
}
I'm not really sure what I'm doing wrong since the examples I found online appear to be doing the same thing.
Frustratingly, the ParameterizedThreadStart delegate type has a signature accepting one object parameter.
You'd need to do something like this, basically:
// This will match ParameterizedThreadStart.
private static void Bar(object x)
{
Bar((int)x);
}
private static void Bar(int x)
{
// do work
}
This is what ParameterizedThreadStart looks like:
public delegate void ParameterizedThreadStart(object obj); // Accepts object
Here is your method:
private static void Bar(int x) // Accepts int
To make this work, change your method to:
private static void Bar(object obj)
{
int x = (int)obj;
// todo
}
It is expecting an object argument so you can pass any variable, then you have to cast it to the type you want:
private static void Bar(object o)
{
int x = (int)o;
// do work
}
You need to change Bar to
private static void Bar(object ox)
{
int x = (int)ox;
...
}
The function you pass to ParameterisedThreadStart needs to have 1 single parameter of type Object. Nothing else.
Method Bar should accept object parameter. You should cast to int inside. I would use lambdas here to avoid creating useless method:
public static void Foo(int x)
{
ParameterizedThreadStart p = new ParameterizedThreadStart(o => Bar((int)o));
Thread myThread = new Thread(p);
myThread.Start(x);
}
private static void Bar(int x)
{
// do work
}
Bar must take an object in parameter, not an int
private static void Bar(object x)
{
// do work
}
Related
Here, I wish to gain a delegate like function pointer, to point to a class method that's in another class (named Inner), and then pass it to a static function, like below:
public class Inner
{
public int M = 3;
public void F() { Console.WriteLine("f"); }
public void G() { Console.WriteLine("g"); }
}
class Program
{
public static void Caller(Action a)
{
a();
}
static void Main(string[] args)
{
var i = new Inner();
var f = i.F;
var g = i.G;
f();//error
g();//error
Program.Caller(f);
Console.WriteLine("Hello World!");
}
}
I'm from c/c++, and in c/c++, function pointer like this is very straight forward, but this C# code fail to compile. I googled and found almost all delegate explanations talks about delegate that points to class method inside itself.
My question is, how to fix the code to make it work?
Coding Seb's answer highlight's the cause of the issue, but doesn't really explain why.
It is because i.F is a method group, and not a specific method pointer. For example, imagine Inner was defined as so:
public class Inner
{
public void F() { Console.WriteLine("f"); }
public void F(string name) { Console.WriteLine(name); }
}
Which method would i.F refer to? F() or F(string)?
For that reason, you need to define the variable type explicitly, or cast the pointer:
Action f = i.F;
Or:
var f = (Action)i.F;
You can not set methods group in implicit variables in C# so if you just change 2 var in Action it's working
public class Inner
{
public int M = 3;
public void F() { Console.WriteLine("f"); }
public void G() { Console.WriteLine("g"); }
}
class Program
{
public static void Caller(Action a)
{
a();
}
static void Main(string[] args)
{
var i = new Inner();
Action f = i.F;
Action g = i.G;
f();
g();
Program.Caller(f);
Console.WriteLine("Hello World!");
}
}
I'd like to do something like this, but it's not possible.(Cann't convert from 'void' to 'System.Action').
class Program
{
public static void Main()
{
int n = 2;
ClassB cb = new ClassB();
cb.SetMethod(ClassA.MethodA(n)); //Cann't convert 'void' to 'System.Action<int>'
}
}
public class ClassA
{
public static void MethodA(int a)
{
//code
}
}
public class ClassB
{
Delegate del;
public void SetMethod(Action<int> action)
{
del = new Delegate(action);
}
public void ButtonClick()
{
del.Invoke();
}
}
public delegate void Delegate(int n);
I can send the argument "n", as second argument in the "setMethod" method, but I would have to store a variable to after pass to "del.Invoke(PARAM)". I'd like to use "del.Invoke()".
You seem to have a misunderstanding of delegates. Delegates represent methods, not method calls. If you supply arguments to a method, it becomes a method call. So here:
cb.setMethod(ClassA.methodA(n));
ClassA.methodA(n) is a method call, and you can't assign that to a delegate.
Basically, you can't pass the parameter at this stage. You have to pass the parameter when you invoke the delegate. e.g.
del.Invoke(5);
But you said you want to always write del.Invoke(), with no arguments. Well, then you should not use an Action<int>, you should just use Action, which does not accept any parameters.
class Program
{
public static void Main()
{
int n = 2;
ClassB cb = new ClassB();
cb.setMethod(() => ClassA.methodA(n));
}
}
public class ClassA
{
public static void methodA(int a)
{
//code
}
}
public class ClassB
{
Delegate del;
public void setMethod(Action action)
{
del = new Delegate(action);
}
public void ButtonClick()
{
del.Invoke();
}
}
public delegate void Delegate();
cb.setMethod(new Action(ClassA.methodA));
It isn't clear whether you want to capture the integer at the call site (e.g. as a closure), or whether you intend passing in a parameter explicitly to the delegate.
Here's the former case, where the value is captured:
public static void Main()
{
var n = 2;
var cb = new ClassB();
cb.setMethod(() => ClassA.methodA(n));
}
The delegate is thus unaware of the captured variable, and is just defined as:
public delegate void Delegate();
If however you do intend passing the int at invoke time, then the value for the int needs to be passed in the ButtonClick:
public static void Main()
{
var cb = new ClassB();
cb.setMethod(ClassA.methodA);
}
public class ClassB
{
Delegate del;
public void setMethod(Action<int> action)
{
del = new Delegate(action);
}
public void ButtonClick()
{
var n = 2;
del.Invoke(n);
}
}
public delegate void Delegate(int n);
Edit - Re Do you think there's a better way
There's no real reason to explicitly require a delegate. Action and Func (and Action<int>, depending on the above) are already delegates. As an improvement, you should check that the action is assigned before invoking it. The null conditional operator will simplify this as _action?.Invoke(). But you can go one step further, and prevent the action from ever being unassigned by requiring it in the constructor:
public class ClassB
{
// Can be readonly if it is assigned only ever once, in the ctor.
private readonly Action _action;
public ClassB(Action action)
{
Contract.Assert(action != null);
_action = action;
}
public void ButtonClick()
{
_action(); // i.e. no need for Invoke or null check.
}
}
i got this Code from an Old post
public delegate void Worker();
private static Thread worker;
public static void Init(Worker work)
{
worker = new Thread(new ThreadStart(work));
worker.Start();
}
public static void Work()
{
string result = testing;
}
I modify the code by adding parameters , when i try to call Init("AA") I am getting an error "Best overload method has some invalid arguments"
The following is the edited code
public delegate void Worker();
private static Thread worker;
public static void Init(Worker work)
{
worker = new Thread(new ThreadStart(work));
worker.Start();
}
public static void Work(string testing)
{
string result = testing;
}
Your Init method takes a delegate and you are passing a string, that is why there is no overload.
you want to do : Init(Work)
PS : your issue has nothing to do with threading.
The problem is your Worker delegate expect take a string parameter. You need to update that and then pass in the parameter e.g.
public delegate void Worker(string str);
private static Thread worker;
public static void Init(Worker work)
{
worker = new Thread(work);
worker.Start("AA");
}
public static void Work(string testing)
{
string result = testing;
}
If you want to pass some data to thread you can use ParametrizedThreadStart, or anonymous method:
private static Thread worker;
public static void Init(string testing)
{
// passing anonymous method, which will capture parameter
worker = new Thread(() => Work(testing));
worker.Start();
}
public static void Work(string testing)
{
string result = testing;
}
private static Thread worker;
public static void Init(string testing)
{
// passing PrametrizedThreadStart delegate
worker = new Thread(Work);
worker.Start(testing); // passing parameter
}
// PrametrizedThreadStart delegate accepts object as parameter
public static void Work(object testing)
{
string result = (string)testing;
}
Please let me know why ParameterizedThreadStart class only allow method which only System.object argument type contain.
public class MainThreadTest
{
public static void Main(string[] args)
{
Thread T = new Thread(new ParameterizedThreadStart(DisplayYOrX));
T.Start("X");
DisplayYOrX("Y");
}
static void DisplayYOrX(object outValue)
{
string Parameter = (string)outValue;
for(int i=0; i<10; i++)
Console.Write(Parameter);
}
}
Why I would like to know about that is I do not want to use type cast syntax again.
string Parameter = (string)outValue;
The reason for the limitation is that ThreadStart isn't a generic delegate and hence it's only capable of passing an object around. This is easy enough to work around though by using a lambda where you directly pass the value.
public static void Main(string[] args) {
ThreadStart start = () => {
DisplayYOrX("X");
};
Thread t = new Thread(start);
t.Start();
...
}
static void DisplayYOrX(string outValue) {
...
}
Version for C# 2.0
public static void Main(string[] args) {
ThreadStart start = delegate {
DisplayYOrX("X");
};
Thread t = new Thread(start);
t.Start();
...
}
I want to pass a method ( of void return type and with no input arguments) as parameter using C#. Below is my sample code. How can I do it ?
public void Method1()
{
... do something
}
public int Method2()
{
... do something
}
public void RunTheMethod([Method Name passed in here] myMethodName)
{
myMethodName();
... do more stuff
}
System.Action will fit the bill:
http://msdn.microsoft.com/en-us/library/system.action.aspx
You've also got various generic versions of Action for methods that have parameters but have a void return type, and Func for methods that return something.
So your RunTheMethod method would look like
public void RunTheMethod(Action myMethod)
{
myMethod();
}
Then you can call it with:
RunTheMethod(Method1);
RunTheMethod(Method2);
As mentioned before, you can use delegates – in your case, you could use System.Action to do exactly that.
public void RunTheMethod(System.Action myMethodName)
{
myMethodName();
... do more stuff
}
Take a look at delegates which act like a pointer to a method
You should look at Delegates to get a solution to your query. They basically serve as a pointer or reference to a function.
Also take a look at this example for a better understanding.
//Delegate
public delegate void OnDoStuff();
class Program
{
static void Main(string[] args)
{
//Pass any of the method name here
Invoker(Method1);
Console.ReadLine();
}
private static void Invoker(OnDoStuff method)
{
method.Invoke();
}
private static void Method1()
{
Console.WriteLine("Method1 from method " + i);
}
private static void Method2()
{
Console.WriteLine("Method2 from method " + i);
}
private static void Method3()
{
Console.WriteLine("Method3 from method " + i);
}
}