8

This is C# 4.0.

I have a class that stores WeakReferences on some Actions like that:

public class LoremIpsum
{
    private Dictionary<Type, List<WeakReference>> references = new Dictionary<Type, List<WeakReference>>();

    public void KeepReference<T>(Action<T> action)
    {
        if (this.references.ContainsKey(typeof(T)))
        {
            this.references[typeof(T)].Add(new WeakReference(action));
        }
        else
        {
            this.references.Add(typeof(T), new List<WeakReference> { new WeakReference(action) });
        }
    }
}

This class has another method allowing to execute the Actions passed to it later but it's of little importance in this question.

and I consume this class this way:

public class Foobar
{
    public Bar Bar { get; set; }

    public void Foo(LoremIpsum ipsum)
    {
        ipsum.KeepReference<Bar>((b) => { this.Bar = b; });
        ipsum.KeepReference<Bar>(this.Whatever);
    }

    public void Whatever(Bar bar)
    {
        // Do anything, for example...:
        this.Bar = bar
    }
}

Bar being a third class in my application.

My question:

In the KeepReference method, how can I know if the Action passed in parameter refers to an anonymous method (this.Bar = b;) or a concrete method (this.Whatever)?

I checked the properties of action. I couldn't find any property on action (like IsAbstract) of a IsAnonymous kind. The underlying type is MethodInfo which makes sense because after compiling I can see in ildasm the anonymous method "became" a normal method on Foobar. In ildasm I can also see that the anonymous method is not a full pink square but a white square surrounded by pink and in its definition there's a call to some CompilerServices classes but I don't know how to take advantage of this back in C#. I'm sure it's possible to get to know about the real nature of action. What am I missing?

Guillaume
  • 1,782
  • 1
  • 25
  • 42
  • Possible duplicate of [How to identify anonymous methods in System.Reflection](http://stackoverflow.com/questions/2503336/how-to-identify-anonymous-methods-in-system-reflection) – user Oct 06 '12 at 09:15
  • @MichaelKjörling It looks like the question I was looking for. I'll give it a try. Even if Pavel's answer is disappointing... – Guillaume Oct 06 '12 at 09:29
  • Pavel does have a point, though. Still, I think that personally, if I needed something like this (I don't quite see why it'd matter in practice whether a method is anonymous or not), I'd rather rely on a `CompilerGeneratedAttribute` on the method, than the intricacies of the compiler's anonymous method naming scheme. – user Oct 06 '12 at 09:34
  • just as a usecase : I'm using some debug helpers that prints the name of the method executed, if applicable. – Pac0 Oct 16 '18 at 16:05

2 Answers2

4

For the sake of having an "accepted" answer on this question, I went as per the link given by Michael Kjörling in his first comment on my question.

if (action.Target.GetType().GetMethods().Where(method => method.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any()).Contains(action.Method))
{
    // ...
}
Guillaume
  • 1,782
  • 1
  • 25
  • 42
  • `if (action.Method.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any()) {...}` looks shorter and should perform a little bit faster – Evgeny Safonov Aug 16 '18 at 19:22
2

Compiler generated methods will always have their names with angled brackets like below

Void <Main>b__0()

so why not just fetch the name and see if it has angled brackets in it.

Action someaction = () => Console.Write("test");
string methodName= RuntimeReflectionExtensions.GetMethodInfo(someaction).ToString();

if(methodName.Contains("<"))
  Console.write("anonymous");

or you can use much better pattern matching with regex

Prabhu Murthy
  • 9,031
  • 5
  • 29
  • 36
  • 2
    Is this guaranteed by the C# spec ("will always"), or simply an implementation detail of the compiler? If it is guaranteed by the C# spec, a reference would be nice. – user Oct 06 '12 at 09:13
  • I thought about this solution but I was hoping the API was providing something "out of the box". – Guillaume Oct 06 '12 at 09:18
  • 1
    I know that angle brackets are disallowed in identifier names by C# (which does not have any bearing on whether or not they are allowed in identifier names in the CLR), but it's important to keep in mind that different compilers (or even different versions of the same compiler) can generate names in different ways. Unless you can definitely state that a certain behavior is guaranteed by the C# or CLR specs, you shouldn't rely on it because it may change at any time. What if in the next version they decide to use `$` (like in Java inner class full names) rather than `<>`? – user Oct 06 '12 at 09:19
  • i certainly dont have anything to back up ,but checking for the presence of the compilergeneratedattribute is a much better option. – Prabhu Murthy Oct 06 '12 at 09:55
  • There will always be some 'illegal characters' in the anonymous method name, so if you check for a valid function name, and it fails, it will be a generated function. – Robert Oct 06 '12 at 10:43