How to identify an anonymous function

I have a class that creates a List<Action<int>> and holds onto them until a later time. This class can add or remove delegates from this list. It works well until people are too fancy. To combat the anonymous function (which cannot be removed) I check that the delegate target is zero. If its value is null, I throw an exception. The problem occurs when there is an anonymous delegate containing a function. This has a purpose, but the same cannot be eliminated. The simplified code below illustrates my concerns.

  public class MyDelegateContainer { List<Action<int>> m_Container = new List<Action<int>>(); public void Add(Action<int> del) { if (del.Target == null) { throw new Exception("No static handlers"); } m_Container.Add(del); } public bool Remove(Action<int> del) { if (m_Container.Contains(del)) { m_Container.Remove(del); return true; } return false; } } public class MyFakeActionClass { public void Test(int temp) { } } class Program { static void Main(string[] args) { bool removed = false; int counter = 0; MyDelegateContainer container = new MyDelegateContainer(); MyFakeActionClass fake = new MyFakeActionClass(); //container.Add(p => { }); //Throws, this is what I want to happen container.Add(fake.Test); //Works, this is the use case removed = container.Remove(fake.Test); //Works, this is the use case Debug.Assert(removed); container.Add(p => { fake.Test(p); counter++; }); //Works but I would like it not to removed = container.Remove(p => { fake.Test(p); counter++; }); //doesn't work Debug.Assert(removed); } } 

I need to determine a way

  p => { fake.Test(p); counter++; } 

is an anonymous function, so I can quit if someone tries it. Thanks for any help

EDIT: I should note that I could use the Action<int> variable for an anonymous function, and everything will work, but Add and Remove will never be in the same area in practice.

+4
source share
6 answers

It is not possible to reliably determine if a function is "anonymous" because all functions have names for the CLR. It is only anonymous within the language that generates it, and it depends on the compiler. You can define the algorithm used by the Microsoft compiler of the current C # only to stop working on C # 5 or Mono.

Since you want users of your type not to write code that uses it incorrectly, you just need to throw an exception at some point, which will cause their program to crash. I would like to make an exception in the Remove function when the target delegate is not found. At this point, your users will still crash, and the only way to fix this is to write a delegate to some extent so that it is replaceable.

As an added bonus, you will catch errors when someone tries to remove delegates twice or who were never added in the first place. The code will look like this:

 public bool Remove(Action<int> del) { if (m_Container.Contains(del)) { m_Container.Remove(del); return true; } throw new ArgumentException("Attempt to remove nonexistent delegate"); } 
+3
source

In your example, the caller is responsible for removing the handler. Thus, if the caller does not want to remove the handler, it will not be deleted, regardless of whether the handler is an anonymous delegate / lambda or not.

My suggestion is to change the delegate container to something like this:

 public class MyDelegateContainer { List<Action<int>> m_Container = new List<Action<int>>(); public Action Add(Action<int> del) { m_Container.Add(del); return new Action(() => { m_Container.Remove(del); }); } } 

The responder is still responsible for removing the handler, but instead of passing the handler back to the container, it receives a β€œtoken”, which it can save and use later to remove the handler.

+4
source

I would use introspection to check method names.

Anonymous methods usually have very predictable names. (I do not remember the exact format, but I am doing some tests, and this should be obvious).

The disadvantage would be that if someone created a non-anonymous method, but decided to call it anonMethod123 (or regardless of format ...), this would be falsely rejected.

+1
source

Of course, you can remove the anonymous method, you just need to have a link to the same anonymous method.

 var myAnonymousMethod = p => { fake.Test(p); counter++; }; container.Add(myAnonymousMethod); removed = container.Remove(myAnonymousMethod); 
0
source

As jonnii explained in a comment, another way you could implement it is with a dictionary:

 public class MyDelegateContainer { Dictionary<string, Action<int>> m_Container = new Dictionary<string, Action<int>>(); public void Add(string key, Action<int> del) { m_Container.Add(key, del); } public bool Remove(string key) { return m_Container.Remove(key); } } 

Then you can easily remove the famous delegate at some arbitrary point in your code, just knowing what name was used to add it:

  container.Add("fake.Test", fake.Test); removed = container.Remove("fake.Test"); Debug.Assert(removed); container.Add("anon", p => { fake.Test(p); counter++; }); removed = container.Remove("anon"); // works! Debug.Assert(removed); 
0
source

An old question that I know, but I think it will be the current (and future) tested way of checking if the method is anonymous:

 bool isAnonymous = !System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(del.Method.Name); 

The runtime name of the anonymous method must be invalid if it is used at compile time to ensure that it does not collide.

0
source

All Articles