If I created a delegate to allow multiple parameters to be passed into the thread start method, as described in this answer, what would be the best way to return a value from the RealStart method to the method which starts the thread?
As I see it, my options are either to create a static variable.
private static Boolean result;
private static String message = "";
public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
var t = new Thread(() => RealStart(param1, param2));
t.Start();
return t;
}
private static void RealStart(SomeType param1, SomeOtherType param2) {
...
}
or to wrap the the delegate in a class
private class TestThread
{
public String message = "";
public Boolean result;
public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
var t = new Thread(() => RealStart(param1, param2));
t.Start();
return t;
}
private static void RealStart(SomeType param1, SomeOtherType param2) {
...
}
}
One issue I see with using a class is that it somewhat negates the point of passing parameters via the delegate as I could pass them into the class when I initialize it.
(Or the third option of not using it in this manner)
Could RealStart ever have a return type?
Are there any pros or cons to using either of the processes described, even if it just comes down to structure/organisation of code?
Use Task, and Task.Result:
// Return a value type with a lambda expression
Task<int> task1 = Task<int>.Factory.StartNew(() => 1);
int i = task1.Result;
// Return a named reference type with a multi-line statement lambda.
Task<Test> task2 = Task<Test>.Factory.StartNew(() =>
{
string s = ".NET";
double d = 4.0;
return new Test { Name = s, Number = d };
});
Test test = task2.Result;
You can use Actions too (for updating form components...):
public TextBox foo = new TextBox();
foo.Text = "foo";
.
.
.
Thread t = new Thread(() => FooBar(p1, p2) );
t.Start();
public void FooBar(Parm parm1, Parm parm2)
{
...
this.foo.BeginInvoke(new Action(() => foo.Text = "bar"));
}
Related
I am working on implementing pub/sub pattern for cache use. The following class is suppose to be used to publish any type of data. And subscribers can attach a callback of Action T on the event. But I couldn't create a generic event at the class level without making the class generic and I don't want to do that. So I have tried to cast the values back and forth to string using JsonSerializer as follows.
public class CacheNotification
{
public Action<string> CachePublished;
public Task Publish<T>(T value)
{
var json = JsonSerializer.Serialize(value);
OnCachePublished(json);
return Task.CompletedTask;
}
public Task Subscribe<T>(Action<T> callback)
{
Action<string> newCallback = (string json) =>
callback(JsonSerializer.Deserialize<T>(json));
CachePublished += newCallback;
return Task.CompletedTask;
}
protected virtual void OnCachePublished(string value)
{
if(CachePublished != null){
CachePublished.Invoke(value);
}
}
}
So the problem is on the subscribe method, the casting I attempted only works for Action string. It fails on Action int or Action object
public Task Subscribe<T>(Action<T> callback)
{
Action<string> newCallback = (string json) =>
callback(JsonSerializer.Deserialize<T>(json));
CachePublished += newCallback;
return Task.CompletedTask;
}
Here is a test I used. This fails for second subscriber
Action<string> sub1Callback = msg =>
{
sub1Counter++;
};
Action<int> sub2Callback = num =>
{
sub2Counter++;
};
var sub1 = await cache.Subscribe(sub1Callback);
var sub2 = await cache.Subscribe(sub2Callback);
await cache.Publish("Value1");
Assert.Equal(1, sub1Counter);
Assert.Equal(1, sub2Counter);
your problem is here:
Action sub2Callback = num =>
after
await cache.Publish("Value1");
Your:
public Task Subscribe<T>(Action<T> callback)
{
Action<string> newCallback = (string json) => callback(JsonSerializer.Deserialize<T>(json));
CachePublished += newCallback;
return Task.CompletedTask;
}
tries to deserialize "Value1" to integer and it correctly fails. It cannot be done.
Try to send integer value instead of "Value1" and it should work.
Another way is to refactor your Subscribe method to be independent of given type, but this cannot be done according to your intentions I guess.
I am trying to start child tasks from parent and Invoke() delegate from collection of delegates in different tasks. But VS is showing me an error - "Delegate does not contain for Invoke..." How can i run this code?
public struct DataStruct {...}
public class DataClass {...}
public class UserClass
{
public delegate DataStruct UserDelegateDS();
public delegate DataClass UserDelegateDC();
public DataStruct MethodDS()
{
return new DataStruct();
}
public DataClass MethodDC()
{
return new DataClass();
}
public void Worker(List<Delegate> delegateCollection)
{
Task<object> parent = new Task<object>(() =>
{
var results = new object [delegateCollection.Count];
for (int i = 0; i < results.Length; i++)
{
new Task(() => results[i] = delegateCollection[i].Invoke(), TaskCreationOptions.AttachedToParent).Start();
}
return results;
});
var cwt = parent.ContinueWith(pTask => Show(pTask.Result));
parent.Start();
}
void ShowResults(object item)
{
var items = item as object [];
foreach(var t in items) {...}
}
public void Main()
{
List<Delegate> delegateCollection = new List<Delegate>();
UserDelegateDS ds = MethodDS;
UserDelegateDC dc = MethodDC;
delegateCollection.Add(ds);
delegateCollection.Add(dc);
Worker(delegateCollection);
}
}
problem screen_from_VS in Worker() method:
new Task(() => results[i] = delegateCollection[i].Invoke(), TaskCreationOptions.AttachedToParent).Start();
Because type Delegate does not specify any function signature, you need to use an actual delegate type to Invoke with strong-type.
Consider using only 1 delegate type that has a return type of object (for which System.Func<object> is recommanded), and wrapping the functions with like ()=>MethodDS() when assigning to a delegate of such type.
Or if you accept significantly lower performance, you can simply call DynamicInvoke() with week-type, instead of Invoke() for type Delegate
I'm trying to create a delegate that will return a delegate. I then want to invoke this delegate, and also invoke the returned inner delegate. My question is: Why is this causing an error? And how to I change this code to accomplish what I'm trying to do?
The error message is 'Method name expected'.
delegate string del();
delegate Delegate nestedDel();
public static void main()
{
nestedDel myNestedDel = () =>
{
del myInnerDel = () => { return "inside"; };
return myInnerDel;
};
Delegate k = myNestedDel();
k(); // Error!!!
}
In short, you've messed up the types. One of the delegates should return the other one, so its return type should simply be the type of the other delegate. In your code example:
delegate string del();
delegate Delegate nestedDel();
you are in fact returning a delegate, but Delegate or MulticastDelegate are just infrastructure base classes and are not invocable directly. By using these classes you're losing information about list of parameters and return values, so simple call() operator cannot work. As Lee mentioned in comments, you could do it by k.DynamicInvoke() but that's.. overkill. Just use a proper type name instead of Delegate.
Working example:
delegate string InnerDel();
delegate InnerDel OuterDel(); // this one returns an instance of Inner delegate
public static void Main()
{
OuterDel myOuterDelegate = () =>
{
InnerDel myInnerDel = () => { return "inside"; };
return myInnerDel;
};
InnerDel k = myOuterDelegate();
k();
}
Personally, I like Func/Actions more than defining my own delegate classes... at least as long as they have at most few parameters. In terms of func/action it would look like this:
public static void Main()
{
Func<Func<string>> myOuterDelegate = () =>
{
Func<string> myInnerDel = () => { return "inside"; };
return myInnerDel;
};
var k = myOuterDelegate();
k();
}
or even..
public static void Main()
{
Func<Func<string>> myOuterDelegate = () => () => { return "inside"; };
var k = myOuterDelegate();
k();
}
Your error is because instances of the Delegate type cannot be invoked with the function call syntax i.e. as k();.
You can call it using DynamicInvoke:
string s = (string)k.DynamicInvoke();
obviously this is prone to runtime errors so a better approach would be to change the return type of nestedDel e.g.
delegate Func<string> nestedDel();
nestedDel myNestedDel = () =>
{
Func<string> myInnerDel = () => { return "inside"; };
return myInnerDel;
};
stringk = myNestedDel();
I have my MainClass and MethodFinder classes. I want to obtain the method name to be run in Main via MethodFinder and execute it.
How can I do that?
What I want is a class with a method that returns Method1 or Method2 (based on some criteria) which then can be run in MainClass's MainMethod!
public MainClass
{
public void Main()
{
var methodFinder = new MethodFinder();
var method = methodFinder.Find();
// Execute method
}
private void Method1(){}
private void Method2(){}
}
You can use the Action type in this situation, as long as the methods have the same signature. If your method took parameters, you could use Action<T>. If it returned a value, you could use Func<TResult>.
public Action Find(SomeType someParameter)
{
if (someCondition)
{
return new Action(() => Method1());
}
else
{
return new Action(() => Method2());
}
}
Note though this method smells like a case where you might want to use Polymorphism to achieve your goals, or possibly Dependency Injection.
You could do this, or use Reflection to be more dynamic.
public class MethodFinder
{
public delegate void MethodSignature();
//these can live whereever and even be passed in
private static void Method1() => Debug.WriteLine("Method1 executed");
private static void Method2() => Debug.WriteLine("Method2 executed");
//maintain an array of possibilities or soemthing.
//perhaps use reflection instead
private MethodSignature[] methods = new MethodSignature[] { Method1, Method2 };
public MethodSignature FindByName(string methodName)
=> (from m in methods
where m.Method.Name == methodName
select m).FirstOrDefault();
}
Usage:
var methodFinder = new MethodFinder();
var method = methodFinder.FindByName("Method2");
method(); //output: "Method2 executed"
I need help. I'm making a programm and i have a problem.
I have a constructor with delegate already:
public delegate bool delIsDone(int curState, int needState);
public Progress(delIsDone doneFunction) { ... }
I need to pass it without creating it outside of creation:
public bool check() { return true }
Progress p = new Progress(check);
I need to do something like this:
Progress p = new ProgressChecker(bool check(int currentProgress, int needProgress) {
return currentProgress < needProgress;
});
Where ProgressChecker is a class that have method that check progress.
In loop i execute this function to get result. If function return "true" it's mean that "Achievement geted" and i need to hold it.
Thx for help
In the constructor you can pass in a function like so:
ProgressChecker(Func<int,int,bool> checker)
That means you can pass a function into the constructor for ProgressChecker
public bool checker (int a, int b)
{
return a < b;
}
var t = new ProgressChecker(checker);
EDIT:
If you want to use the delegate, then in the ProgressChecker class, the constructor must take in that delegate type:
private delIsDone delIsDone;
public ProgressChecker(delIsDone delIsDone)
{
this.delIsDone = delIsDone;
}
You can the pass a delegate instance like so:
public class Program
{
public delegate bool delIsDone(int curState, int needState);
public static bool checkNumbers(int a, int b)
{
return a < b;
}
public static void Main(string[] args)
{
var t = new ProgressChecker(new delIsDone(checkNumbers));
// OR var t = new ProgressChecker(new delIsDone((a, b) => { return a < b; }));
}
}
You can also create Expression Trees, it is my snippet for it (it can be easly converted to your example)
//easy way
Expression<Action<int>> printExpr = (arg) => Console.WriteLine(arg);
printExpr.Compile()(10);
//hard way
ParameterExpression param = Expression.Parameter(typeof(int), "arg");
MethodCallExpression methodCall = Expression.Call
(
typeof(Console).GetMethod("WriteLine", new[]
{
typeof(int)
}
),
param
);
Expression.Lambda<Action<int>>(methodCall, param).Compile()(10); //execution
More information ca be gathered at Generating Dynamic Methods with Expression Trees