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();
...
}
Related
I have some code that is using a third-party library that I can't bypass. This library provides some auxiliary features that I need. At this time, my code is setup like this:
static Engine engine = new Engine();
static void Main(string[] args)
{
engine.Execute(MyCode);
}
private static void MyCode()
{
// my code goes here
}
Here's my challenge: I have to instantiate some code before MyCode can use it because that instantiation must hit a database and takes longer than the threshold allowed by Engine. I can't use a static variable because multiple instances will be necessary. Which basically means, I want something like this:
static Engine engine = new Engine();
static void Main(string[] args)
{
MyClass c = new MyClass();
c.Initialize(); // This is the db call
engine.Execute(MyCode); // This line is the problem
}
private static void MyCode(MyClass c)
{
// my code goes here
c.DoStuff();
}
My problem is, I basically need to create an overloaded method that takes a parameter. However, the Execute method in the third-party library doesn't let me do that. Is there some C# syntactial way I can do this that I'm missing?
You're looking for lambda expressions:
engine.Execute(() => MyCode(c));
I'm assuming that Engine.Execute takes an instance of Action.
You could make the MyCode function an instance member function on MyClass, then pass MyClass.MyCode to Engine.Execute as an Action.
public class Engine
{
public void Execute(Action action)
{
action.Invoke();
}
}
public class MyClass
{
public void Initialize()
{
System.Threading.Thread.Sleep(500); //Simulate some work.
}
public void Run()
{
// I've renamed it from MyCode to Run, but this method is essentially your
// my code method.
Console.WriteLine($"I'm being run from the engine! My Id is {_id}.");
}
private readonly Guid _id = Guid.NewGuid();
}
public static class Program
{
static void Main(string[] args)
{
var engine = new Engine();
var c = new MyClass();
c.Initialize();
engine.Execute(c.Run);
}
}
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 am trying to figure out how to multi-thread an application. I am stuck trying to find the entry point to start the thread.
The thread that I am trying to start is : plugin.FireOnCommand(this, newArgs);
...
PluginBase plugin = Plugins.GetPlugin(Commands.GetInternalName(command));
plugin.FireOnCommand(this, newArgs);
...
The FireOnCommand method is:
public void FireOnCommand(BotShell bot, CommandArgs args)
I am not having any luck using ParameterizedThreadStart or ThreadStart, I can't seem to get the syntax correct.
EDIT: Tried both
Thread newThread =
new Thread(new ParameterizedThreadStart(plugin.FireOnCommand(this, newArgs)));
and
Thread newThread =
new Thread(new ThreadStart(plugin.FireOnCommand(this, newArgs)));
In .NET 2, you would need to create a method for this, with a custom type. For example, you could do:
internal class StartPlugin
{
private BotShell bot;
private CommandArgs args;
private PluginBase plugin;
public StartPlugin(PluginBase plugin, BotShell bot, CommandArgs args)
{
this.plugin = plugin;
this.bot = bot;
this.args = args;
}
public void Start()
{
plugin.FireOnCommand(bot, args);
}
}
You can then do:
StartPlugin starter = new StartPlugin(plugin, this, newArgs);
Thread thread = new Thread(new ThreadStart(starter.Start));
thread.Start();
Here is some example code:
class BotArgs
{
public BotShell Bot;
public CommandArgs Args;
}
public void FireOnCommand(BotShell bot, CommandArgs args)
{
var botArgs = new BotArgs {
Bot = bot,
Args = args
};
var thread = new Thread (handleCommand);
thread.Start (botArgs);
}
void handleCommand (BotArgs botArgs)
{
var botShell = botArgs.Bot;
var commandArgs = botArgs.Args;
//Here goes all the work
}
You should not really create your own Thread object unless you are planning on interacting with it, specifically with the thread it represents. And with interacting, I mean stopping it, starting it again, aborting it, pausing it or anything like that. If you have just an operation that you want asynchronized, you should go for the ThreadPool instead. Try this:
private class FireOnCommandContext
{
private string command;
private BotShell bot;
private CommandArgs args;
public FireOnCommandContext(string command, BotShell bot, CommandArgs args)
{
this.command = command;
this.bot = bot;
this.args = args;
}
public string Command { get { return command; } }
public BotShell Bot { get { return bot; } }
public CommandArgs Args { get { return args; } }
}
private void FireOnCommandProc(object context)
{
FireOnCommandContext fireOnCommandContext = (FireOnCommandContext)context;
PluginBase plugin = Plugins.GetPlugin(Commands.GetInternalName(fireOnCommandContext.Command));
plugin.FireOnCommand(fireOnCommandContext.Bot, fireOnCommandContext.Args);
}
...
FireOnCommandContext context = new FireOnCommandContext(command, this, newArgs);
ThreadPool.QueueUserWorkItem(FireOnCommandProc, context);
Note that this will do the work in a separate thread, but it will NOT notify you once its done, or anything.
Please also note that I was guessing your command to be of string type. If it isn't, just set the type to the correct one.
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;
}
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
}