C# Extension methods for Existing methods - c#

How can I write an extension method for an existing method like :
static class Extensions
{
public static void RunAsThread(this Action func)
{
Thread t = new Thread(delegate()
{
try
{
if (func != null)
func();
}
catch (ThreadInterruptedException tie) { }
catch (ThreadAbortException tae) { }
catch (Exception ex)
{
Logger.LogDebug(ex);
}
});
t.Start();
}
}
is there any way that i can run this methods perfectly in the way i wanted
class WorkingClass
{
public void Work()
{
//Works fine
((Action)DoSomething).RunAsThread();
//Works fine
Extensions.RunAsThread(DoSomething);
//But I really need this to work
DoSomething.RunAsThread();
}
private void DoSomething()
{
//Do Something
}
}
I really wanted to make DoSomething.RunAsThread() work.
I tried to change "static void RunAsThread(this delegate .... or this Delegate)".
Could not do it properly.
Is there any work around for that? Is there any way for that?

No, you can't do this, as DoSomething is not a type, it's a method.
Also, just because you can attach an extension method to a type it doesn't mean you should..!

If DoSomething doesn't have to be an actual method, a slight tweak would make this compile:
class WorkingClass
{
public void Work()
{
//Works fine
((Action)DoSomething).RunAsThread();
//Works fine
Extensions.RunAsThread(DoSomething);
//But I really need this to work
DoSomething.RunAsThread();
}
private Action DoSomething = () =>
{
//Do Something
};
}
Whether that fits in with everything else you're writing or not, I couldn't say.

DoSomething is just a "Method group" it will be implicitly converted to Action or compatible delegate type whenever possible.
DoSomething itself not a Delegate, so not possible. but you could do the following with the help of implicit method group conversion.
Action a = DoSomething;
a.RunAsThread();

Related

Async Lambda Issue

Updated code (as per comment): still doesn't work
I am trying to create an extension method on Task to call my async database calls (fire and forget), however I am getting a compilation error:
Error CS4010
Cannot convert async lambda expression to delegate type 'Func<T>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'Func<T>'. AsyncTaskExtension
This is my code:
public static void ExecuteTask<T>(this Task<T> BackgroudJob, Action<T> UIJob, Action<Exception> OnError = null) where T : struct
{
Func<T> work = async () =>
{
T ret = default(T);
try
{
ret = await BackgroudJob;
UIJob(ret);
//throw new Exception("My exception !!!");
}
catch (Exception ex)
{
try
{
if (OnError != null)
{
OnError(ex);
}
System.Diagnostics.Debug.WriteLine(ex);
}
catch { }//eat exception
}
return ret;
};
work();
}
I am trying to create an extension method on Task to call my async database calls(fire and ferget)
OK, I have to say that this is a really, really bad idea!
"Fire and forget" means: "I don't care when this code completes. Or if it completes." Corollary: "I am perfectly OK with losing database writes during an appdomain recycle, process recycle, reboot, or pod replacement; and I am happy with not having any logs or other notifications about said data loss."
I cannot imagine how this would ever be acceptable for a database write operation. At most, fire-and-forget is sometimes used for things like updating caches. Some people think it's OK for emails, too, but I prefer a simple queue.
To make the method fire-and-forget, change the return type to void and the Func<T> to an Action:
public static void CreateFireAndForgetWork<T>(this Task<T> Job, Action<Exception> OnError = null) where T : struct
{
Action work = async () =>
{
try
{
await Job;
}
catch (Exception ex)
{
...
}
};
work();
}
This code does result in an async void lambda expression (since it is converted to an Action). Normally, this is a bad idea, but it's here because the code is doing fire-and-forget (which, as noted at the beginning of this post, is a bad idea IMO).
Ok finally it worked
public static void ExecuteTask<T>(this Task<T> BackgroudJob, Action<T> UIJob, Action<Exception> OnError = null) where T : struct
{
Action work = async () =>
{
T? ret = null;
try
{
ret = await BackgroudJob;
//throw new Exception("My exception !!!");
}
catch (Exception ex)
{
try
{
if (OnError != null)
{
OnError(ex);
}
System.Diagnostics.Debug.WriteLine(ex);
}
catch { }//eat exception
}
if (ret.HasValue)
{
UIJob(ret.Value);
}
};
work();
}

How to pass array'method signature C#

Now I have a ConcurrentDictionary .
I want to invoke the IDataExchangeServiceCallBack's method.
the IDataExchangeServiceCallBack's code below:
[ServiceContract]
public interface IDataExchangeServiceCallBack
{
[OperationContract(IsOneWay = true)]
void SendResult(string msg);
[OperationContract(IsOneWay = true)]
void Receive(List<RealDataModel> models);
}
In other class, I want invoke dict's method foreach.
such as
public void Receive(List<RealDataModel> models)
{
Broast(o => nameof(o.Receive), models);
}
public void SendResult(string msg)
{
Broast(o => nameof(o.SendResult), msg);
}
And Broast method below:
private void Broast(Func<IDataExchangeServiceCallBack, string> funcMethodName, params object[] args)
{
if (_callbackChannelList.Count > 0)
{
var callbackChannels = _callbackChannelList.ToArray();
foreach (var channel in callbackChannels)
{
try
{
var type = channel.Value.GetType();
// fetch the method's name.
var methodName = funcMethodName.Invoke(channel.Value);
// reflect & get the method
var methodInfo = type.GetMethod(methodName);
//invoke
methodInfo?.Invoke(channel.Value, args);
}
catch (Exception ex)
{
_callbackChannelList.TryRemove(channel.Key, out _);
}
}
}
}
Now my question is how to implement above code without reflect, it's there any better solution.
The Expression can implement it ?
I'm not familiar with Expression.
Thanks.
I don't understand how you got to the solution you have. Regardless of the type of o, the expression, for example, nameof(o.Receive) will always result in the string "Receive". It seems to me you could just pass nameof(IDataExchangeServiceCallBack.Receive) to the method instead of passing a delegate.
That said, I also don't understand why you are looking to use reflection or Expression. It appears to me that, at the call site, you know the type of object you're dealing with, the method you want to call, and the arguments you want to pass. So you could just pass a delegate that does all that. For example:
private void Broast(Action<IDataExchangeServiceCallBack> callback)
{
foreach (var channel in _callbackChannelList.ToArray())
{
try
{
//invoke
callback(channel.Value);
}
catch (Exception ex)
{
_callbackChannelList.TryRemove(channel.Key, out _);
}
}
}
Used like:
public void Receive(List<RealDataModel> models)
{
Broast(o => o.Receive(models));
}
public void SendResult(string msg)
{
Broast(o => o.SendResult(msg));
}
Note that I've cleaned up the Broast() method a bit. There's very little overhead calling ToArray() on an empty collection, and it simplifies the code significantly to remove the Count > 0 check. Code is always easier to write and read later if you can remove unnecessary conditional checks.

add method call to each method in a class

I have class with many methods:
public class A {
public string method1() {
return "method1";
}
public string method2() {
return "method2";
}
public string method3() {
return "method3";
}
.
.
.
public string methodN() {
return "methodN";
}
}
I would like to add call to doSomething() in each method, for example:
public string methodi() {
doSomething();
return "methodi";
}
What is the best way to do so? Is there any suitable design pattern?
This is a typical use case for AOP (aspect oriented programming). You'd define the insertion points for the method calls and the AOP engine adds the correct code to the class file. This is often used when you want to add log statements without cluttering your source files.
For java you could add the aspectj library
For C# and .NET have look at this blog. Looks like a good starter.
Using AOP is already a good answer, it was my first idea too.
I tried to figure out a good way doing it without AOP though and came up with this idea (using the Decorator pattern):
interface I {
String method1();
String method2();
...
String methodN();
}
class IDoSomethingDecorator implements I {
private final I contents;
private final Runnable commonAction;
IDoSomethingDecorator(I decoratee, Runnable commonAction){
this.contents = decoratee;
this.commonAction = commonAction;
}
String methodi() {
this.commonAction().run();
return contents.methodi();
}
}
You could then decorate the construction of A (which implements I):
I a = new IDoSomethingDecorator(new A(),doSomething);
It is basically no rocket science and in fact results in more code than your first idea, but you are able to inject the common action and you separate the additional action from the class A itself. Further, you can turn it off easily or use it only in tests, for instance.
Why not having a single function?
public string methodi(int i) {
doSomething();
return "method" + i.toString();
}
Or you may write a function which takes an Func parameter and call this function instead of your functions.
public string Wrapper(Func<string> action)
{
doSomething();
return action();
}
and call your functions from this function;
string temp = Wrapper(method1);
You could use reflection.
public String callMethod(int i) {
doSomething();
java.lang.reflect.Method method;
try {
method = this.getClass().getMethod("method" + i);
} catch (NoSuchMethodException e) {
// ...
}
String retVal = null;
try {
retVal = method.invoke();
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) { }
return retVal;
}

MethodInvoker + lambda + arguments + CrossThread Operation

I'm using this to change something on other thread:
MethodInvoker m = () => { login_submit.Text = "Login"; };
if (InvokeRequired)
{
BeginInvoke(m);
}
else
{
Invoke(m);
}
this is working fine.
How can I pass argumets to that lamba expression?
I want to do sth like that:
MethodInvoker m = (string txt) => { login_submit.Text = txt; };
if (InvokeRequired)
{
BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
Invoke(m); // I need to pass txt string in some way here.
}
If this is a common scenario for you, I suggest writing an extension method:
public static class ControlExtensions
{
public static void EnsureInvokeAsync(this Control control, Action action)
{
if (control.InvokeRequired) control.BeginInvoke(action);
else action();
}
}
class MyControl : UserControl
{
void M(string s)
{
// the lambda will capture the string in a closure
// the compiler does all the hard work for you
this.EnsureInvokeAsync(() => _button.Text = s);
}
}
Also, you should look into using BackgroundWorker or tasks for async operations.
If InvokeRequired is false then you don't need to worry about invoking anything at all - you're already on the right thread.
A better solution might be something like this:
public delegate void InvokerDelegate(string data);
public void DoStuff(string data){
login_submit.Text = data;
}
and then when calling it do:
if (InvokeRequired){
Invoke(InvokerDelegate(DoStuff), "something");
}
else{
DoStuff("Something");
}
A fairly common pattern you will see is to do something like this for functions that manipulate the GUI in a multithreaded environment
public delegate void InvokerDelegate();
public void DoGuiStuff(){
if (login_submit.InvokeRequired){
login_submit.Invoke(InvokerDelegate(DoGuiStuff));
return;
}
login_submit.Text = "Some value";
}
If you use the above pattern the function checks to see if an invoke is required and if so Invokes itself on the right thread. It then returns. When it invokes itself the check to see if an invoke is required returns false so it doesn't bother invoking itself again - it just runs the code.
Edit: I just went back to winforms and tried to use that pattern only to spend a couple of frustrating minutes trying to work out why I couldn't invoke a lambda. I thought I'd better come back and update this answer to add the required casting in case anyone else tried to use it.
MethodInvoker is a delegate type that doesn't have any parameters. If I understand you correctly, you can do it like this:
string txt = "some text";
MethodInvoker m = () => { login_submit.Text = txt; };
You can use closures to pass the value into the lambda's body.
string value = "Login";
MethodInvoker m = () => { login_submit.Text = value; };
if (InvokeRequired)
{
BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
Invoke(m); // I need to pass txt string in some way here.
}
or you can use class member's data

Anonymous method as parameter to BeginInvoke?

Why can't you pass an anonymous method as a parameter to the BeginInvoke method? I have the following code:
private delegate void CfgMnMnuDlg(DIServer svr);
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke((CfgMnMnuDlg)ConfigureMainMenu,
new object[] { server});
}
else
{
// Do actual work here
}
}
I'm trying to avoid declaring the delegate. Why can't I write something like the below instead? Or can I, and I just can't figure out the correct syntax? The below currently generates an:
Argument type 'Anonymous method' is not assignable to parameter type 'System.Delegate'
Ok, that's right of course, but is there some other syntax I can use to do this (avoid having to declare a separate delegate in order to use BeginInvoke()?
(Being able to do this would fit in neatly with the concept of using anon methods/lamdas in place of explicit delegates which works so cleanly everywhere else.)
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke( // pass anonymous method instead ?
delegate(DIServer svr) { ConfigureMainMenu(server);},
new object[] { server});
}
else
{
// Do actual work here
}
}
Try this:
control.BeginInvoke((MethodInvoker) delegate { /* method details */ });
Or:
private void ConfigureMainMenu(DIServer server)
{
if (control.InvokeRequired)
{
control.BeginInvoke(new Action<DIServer >(ConfigureMainMenu), server);
}
else
{
/* do work */
}
}
Or:
private void ConfigureMainMenu(DIServer server)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
// Private variable
_methodInvoker = new MethodInvoker((Action)(() => ConfigureMainMenu(server)));
_methodInvoker.BeginInvoke(new AsyncCallback(ProcessEnded), null); // Call _methodInvoker.EndInvoke in ProcessEnded
}
else
{
/* do work */
}
}
You should be able to write something like this:
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke(new Action<DIServer>(ConfigureMainMenu),
new object[] { server});
}
else
{
// Do actual work here
}
}
You could write an extension method that would wrap anonymous methods, and even take care of the InvokeRequired semantics:
public static void InvokeAction(this Control ctl, Action a)
{
if (!ctl.InvokeRequired)
{
a();
}
else
{
ctl.BeginInvoke(new MethodInvoker(a));
}
}
This would allow you to do:
control.InvokeAction(delegate() { ConfigureMainMenu(server); });
You can do this in a single method by calling invoking yourself:
ClassData updData = new ClassData();
this.BeginInvoke(new Action<ClassData>(FillCurve),
new object[] { updData });
...
public void FillCurve(ClassData updData)
{
...
}
For completely anonymous methods with a limited number of parameters:
Func<int, int?> caller = new Func<int, int?>((int param1) =>
{
return null;
});
caller.BeginInvoke(7, new AsyncCallback((IAsyncResult ar) =>
{
AsyncResult result = (AsyncResult)ar;
Func<int, int?> action = (Func<int, int?>)result.AsyncDelegate;
action.EndInvoke(ar);
}), null);
You can use one of the other Func delegate types as needed.
I've tried a bunch of different methods but none work. ie...
// Fails -- cannot convert lamda to System.Delegate
mnMnu.BeginInvoke( (DIServer svr)=> {ConfigureMainMenu(server);}, new object[] server);
// Fails -- cannot convert anonymous method to System.Delegate
mnMnu.BeginInvoke( new delegate(DIServer svr){ConfigureMainMenu(server);}, new object[] server);
So, the short answer is no. You could create short helper delegates in the given context and use lambdas to make it a bit neater but that's pretty much it.
EDIT: Turns out I'm wrong. The methodinvoker answer below works.
See this page

Categories

Resources