I have following constructor in my class, which initializes my task:
public ReportGeneratorThread(Func<int, bool> getPermission, Action<object> a)
{
this.action = a;
this.t = new Task(this.action = this.InvokedAction, this.cancellationToken);
this.getPermission = getPermission;
}
The InvokedAction method, which will be invoked by the task is defined such as:
private void InvokedAction(object obj)
{
Debug.WriteLine(DateTime.Now.ToLongTimeString() + " Task " + this.t.Id + " has STARTED Generating a report");
this.GenerateReport();
throw new ArgumentException("For testing purpose");
}
The problem occurs when I want to invoke this method with an int rather than an object, since this is not accepted by the task. Is there any approach of how I can invoke this method with an int value with an:
Action<int>
Since you can't call Action<int> with argument of type object you need to convert it manually. Note that it would be fine if requirement is other way around - you can easily pass Action<object> where Action<int> is expected.
... new Task( v => intAction((int)v),...
You may need to handle cast exceptions if you can't guarantee that argument is always integer.
Can you box your int before invoking?
int i = 123;
object o = i;
Related
I'm trying to call buildRangedJobCache with SelectionRange S as the passed in parameter, But the Compiler(visual studio 2010) gives the error: Method Name Expected below is the call that gives issue:
private void retrieveSeveralDaysJobs(SelectionRange S)
{
ignoreUpdates = false;
this.SetStatus(DataLogUIStrings.strRetrievingJobInformation);
Thread buildIndexThread = new Thread(new ThreadStart(buildRangedJobCache(S)));
buildIndexThread.Priority = ThreadPriority.Lowest;
buildIndexThread.Start();
}
and here is the function buildRangedJobCache(SelectionRange S):
private void buildRangedJobCache(SelectionRange S)
{
this.Cursor = Cursors.AppStarting;
try
{
if (DataStore == null)
{ throw new Exception("Error: DataStore is null, Unable to retrieve jobs."); }
lock (((ICollection)jobs).SyncRoot)
{
for (DateTime Day = S.Start; Day <= S.End; Day.AddDays(1))
{
this.RangeJobs.AddRange(DataStore.GetJobsListForDay(JobDateToDisplay.GetValueOrDefault(DateTime.Today)));
}
}
this.SetStatus(string.Format(DataLogUIStrings.strRetrievedSummaryInformation, this.jobs.Count));
}
catch (Exception e)
{
Log.Write(e);
}
this.Cursor = Cursors.Default;
}
also I've linked to here: Delegate: Method name expected error
as this solution didn't work for me.
**update: apparently it isn't clear, the solution of putting:
Thread buildIndexThread = new Thread(new ThreadStart(buildRangedJobCache));
does the same issue.
Pass only method name when creating delegate:
Thread buildIndexThread = new Thread(new ThreadStart(buildRangedJobCache));
Also ThreadStart delegate should not receive any arguments. It is defined as
public delegate void ThreadStart();
So, your buildRangedJobCache method signature do not match ThreadStart delegate signature. If you want to pass some parameters to thread, you should use ParameterizedThreadStart delegate, which accepts parameter of type object:
private void retrieveSeveralDaysJobs(SelectionRange range)
{
ignoreUpdates = false;
this.SetStatus(DataLogUIStrings.strRetrievingJobInformation);
// pass ParameterizedThreadStart delegate
Thread buildIndexThread = new Thread(BuildRangedJobCache);
buildIndexThread.Priority = ThreadPriority.Lowest;
buildIndexThread.Start(range); // provide parameter for thread
}
private void BuildRangedJobCache(Object obj)
{
SelectionRange range = (SelectionRange)obj; // cast to your type
// code
}
The Thread constructor requires a delegate (either ThreadStart or ParametrizedThreadStart). You're trying to create the ThreadStart delegate, but you can create a delegate out of a method, not method invocation expression.
So, if your method didn't have a parameter, the following would work:
new Thread(new ThreadStart(buildRangedJobCache));
and so would (because the compiler can infer which delegate are you creating):
new Thread(buildRangedJobCache);
If you need to pass a parameter to your method, you can use ParametrizedThreadStart and the overload of Start() that takes a parameter. But this means you have to change your method to have object parameter and cast it to your type inside the method.
I think a better option would be to use a lambda:
new Thread(() => buildRangedJobCache(S));
This creates an anonymous method that matches ThreadStart and remembers the variable S. This way, you don't need the signature of your method and you also don't need any casting.
Overview:
I am writting an application to dynamically load .dlls and call their methods.
Since the .dlls are doing heavy i/o in background, i've made callbacks to notify the UI about what's happening "down there"
Pieces of Code:
dllName = (string) e.Argument;
// Assembling Complete path for the .dll file
completePath = Path.Combine(ConfigurationManager.AppSettings["DllsFolder"], dllName);
Assembly assembler = Assembly.LoadFrom (completePath);
// Creating Instance of Crawler Object (Dynamically)
dllWithoutExtension = Path.GetFileNameWithoutExtension (dllName);
Type crawlerType = assembler.GetType (dllWithoutExtension + ".Crawler");
object crawlerObj = assembler.CreateInstance (crawlerType.FullName);
// Fetching reference to the methods that must be invoked
MethodInfo crawlMethod = crawlerType.GetMethod ("StartCrawling");
MethodInfo setCallbackMethod = crawlerType.GetMethod ("SetCallback");
So far, so good.
The problem is that, even tho i have declared the "callback" method
public void Notify (string courseName, int subjects, int semesters)
{
string course = courseName;
int a = subjects;
int b = semesters;
}
This code works (just to test if the callback declaration is working)
Crawler crawler = new Crawler();
crawler.SetCallback (Notify);
crawler.StartCrawling();
While this, does not work (this is what i am trying to fix. Calling the .dll method dinamically, passing the callback as argument)
setCallbackMethod.Invoke(crawlerObj, new object[] { Notify }); // this method fails, bc its a callback parameter
crawlMethod.Invoke(crawlerObj, new object[] {true} ); // This method works, bc its a bool parameter
I assume you have a delegate type like this for passing the method to SetCallback:
public delegate void CrawlerCallback(string courseName, int subjects, int semesters);
Then you may pass the Notify method if you cast it to this delegate type like this:
setCallbackMethod.Invoke(crawlerObj, new object[] { (CrawlerCallback)Notify });
In the code below, I am trying to execute a method, which returns a value, in another thread. However, it just DOES NOT work!!!
public void main()
{
lstChapters.DataContext = await TaskEx.WhenAll(LoadChapters());
}
//CAN'T use async in this function, it requires Task<> which
//Error appears on the code inside []
public [async Task<object>] Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
dictChapters data = await IQ_LoadQuranXML.LoadChapters(TypeIndex);
}
internal static async Task< IEnumerable<dictChapters>> LoadChapters()
{
var element = XElement.Load("xml/chapters.xml");
Task < IEnumerable < dictChapters >> something = (Task<IEnumerable<dictChapters>>) await TaskEx.Run(delegate
{
IEnumerable<dictChapters> Chapters =
from var in element.Descendants("chapter")
orderby var.Attribute("index").Value
select new dictChapters
{
ChapterIndex = Convert.ToInt32(var.Attribute("index").Value),
ChapterArabicName = var.Attribute("name").Value,
ChapterType = var.Attribute("type").Value,
};
return Chapters;}
);
return something; //An ERROR on this line
}
//Overriding method which does not return IEnumerable type. And it accepts index as integer.
internal static dictChapters LoadChapters(string chIdx = "0")
{
int chIdxInt = Convert.ToInt32(chIdx);
List<dictChapters> Chapters = (List<dictChapters>) LoadChapters(); // ERROR is on this line too
return Chapters.ElementAt(chIdxInt - 1); //index of chapter in the element starts from 0
}
The Error is:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<iq_main.dictChapters>>' to 'System.Collections.Generic.IEnumerable<iq_main.dictChapters>'. An explicit conversion exists (are you missing a cast?)
And the Other error is..
Cannot convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List<iq_main.dictChapters>>' to 'System.Collections.Generic.List<iq_main.dictChapters>
When I cast "something" explicitly like return (IEnumerable<dictChapters>) something then at runtime, I get "InvalidCastException".
Actually, you'll be getting a runtime cast error earlier than that. The problem is your cast of the TaskEx.Run result. When you await something, the Task wrapper is removed.
public void main()
{
lstChapters.DataContext = await LoadChapters();
}
internal static Task<List<dictChapters>> LoadChapters()
{
return TaskEx.Run(delegate
{
var element = XElement.Load("xml/chapters.xml");
IEnumerable<dictChapters> Chapters =
from var in element.Descendants("chapter")
orderby var.Attribute("index").Value
select new dictChapters
{
ChapterIndex = Convert.ToInt32(var.Attribute("index").Value),
ChapterArabicName = var.Attribute("name").Value,
ChapterType = var.Attribute("type").Value,
};
return Chapters.ToList();
});
}
There are a few other problems with your code as well. Remember that enumerations like this are lazily executed. You probably want to return Chapters.ToList(); so that the XML parsing happens on the thread pool thread.
Since you did await on the TaskEx.Run, you have the enumerable coming back, not a task.
For what you're doing, I'd recommend just keeping LoadChapters as normal/sync code, then either just invoke it via Task.Run, or call it as-is.
Due to deferred execution, AFAICT your current code doesn't really help anything since you're still doing the Load synchronously.
The Task.WhenAll in main could be removed, just await LoadChapters (or whatever the asynchronous method is
I have a calculating thread function which invokes message function from other thread using Invoke and I want that calculating thread to get value(of valuetype, like integer) from that message function. How can I do this?
The problem is that I still get old value of x variable after Invoke(...) and I expect value of 15
delegate void mes_del(object param);
void MyThreadFunc()
{
...
int x = 5;
object [] parms = new object []{x};
Invoke(new mes_del(MessageFunc), (object)parms);
...
}
void MessageFunc(object result)
{
int res = 15;
(result as object[])[0] = res;
}
I tried some approaches like using object[], object as parameters with no success. I though boxing/unboxing operations should occur in such a case but they don't.
Should I use auxiliary type like it is done in .NET event mode and create mediator object like
class holder
{
public int x;
}
int x = 5;
object [] parms = new object []{x};
What the above code does is declare a local variable, assign it the value 5, then construct an object[] array containing one element which is a copy of that local variable.
You then pass this array into your Invoke call.
I think what you'll find is that after Invoke is called, parms[0] is 15. But this does not affect x, which would actually have to be passed as a ref parameter for any method to be able to modify its local value.
What I've seen done before is something like this:
class Box<T>
{
public T Value { get; set; }
}
Then you could do:
void MyThreadFunc()
{
var x = new Box<int> { Value = 5 };
// By the way, there's really no reason to define your own
// mes_del delegate type.
Invoke(new Action<Box<int>>(MessageFunc), x);
}
void MessageFunc(Box<int> arg)
{
arg.Value = 15;
}
Are you talking about Control.Invoke from Windows Forms? If yes, the method can also return a result, so you can write:
delegate int mes_del(int param);
void MyThreadFunc() {
int x = 5;
object [] parms = new object []{x};
x = (int)Invoke(new mes_del(MessageFunc), x);
// you'll get a new value of 'x' here (incremented by 10)
}
int MessageFunc(int result) {
return result + 10;
}
Your code probably didn't work, because you were accessing x instead of picking a new value from the array (that should be modified). However, using an overload that returns a new value should be a much clearer solution.
Just return value from method
void MyThreadFunc()
{
...
int x = 5;
object [] parms = new object []{x};
var callResult = (int)Invoke((Func<object,int>)MessageFunc, (object)parms);
...
}
int MessageFunc(object result)
{
int res = 15;
return res;
}
Perhaps the best answer to your question is in .NET 4.0 System.Threading.Tasks
Here the main thread is blocked till the Result is returned by the method called on the other thread. If the result is already returned by the main thread reaches the WriteLine there is no blocking.
Task task = Task.Factory.StartNew(SomeMethod);
Console.WriteLine(task.Result);
public static string SomeMethod()
{
return "Hello World";
}
OR
Task task = Task.Factory.StartNew(() => { return "Hello World"; } );
Console.WriteLine(task.Result);
Check this blog for more interesting samples.
I want to create a method like this:
private static void AddOrAppend<K>(this Dictionary<K, MulticastDelegate> firstList, K key, MulticastDelegate newFunc)
{
if (!firstList.ContainsKey(key))
{
firstList.Add(key, newFunc);
}
else
{
firstList[key] += newFunc; // this line fails
}
}
But this fails because it says you can't add multicast delegates. Is there something I'm missing? I thought the delegate keyword was just shorthand for a class which inherits from MulticastDelegate.
firstList[key] = (MulticastDelegate)Delegate.Combine(firstList[key],newFunc);
with test:
var data = new Dictionary<int, MulticastDelegate>();
Action action1 = () => Console.WriteLine("abc");
Action action2 = () => Console.WriteLine("def");
data.AddOrAppend(1, action1);
data.AddOrAppend(1, action2);
data[1].DynamicInvoke();
(which works)
But tbh, Just use Delegate in place of MulticastDelegate; this is largely a hangover from something that never really worked. Or better; a specific type of delegate (perhaps Action).