views:

89

answers:

2

I am writing an extension method where I happen to need the field name that the extension method is needed within the extension method. I can not figure out how to do this.

My code:


Extension method:

public static Validate Demand<T>(this T parameter)
{
    string name = ...
    var field = GetField(parameter);
    return Validation.CreateValidation(parameter, field, name);
}

Use case:

void SomeMethod(T someParameter)
{
   someParameter.Demand();
}

I want name to hold someParameter.

+1  A: 

You can't. It would be nice in a few cases, particularly for argument checking, but it's just not possible. As an example of where it would be handy, I have this method:

internal static void ThrowIfNull<T>(this T argument, string name)
    where T : class
{
    if (argument == null)
    {
        throw new ArgumentNullException(name);
    }
}

which I have to call with:

foo.ThrowIfNull("foo");

It's better than nothing, but it would be nice not to have to supply the "foo" bit. Unfortunately, there's just no way of doing it. You could probably write a post-build IL rewriter which determined how the method was called and rebuilt it from that, but that's rather more work than the benefit, I suspect :)

Jon Skeet
A: 

Here's one way to get what I think you're asking for:

static class Argument
{
    public static void NotNull(Expression<Func<Func<object>>> arg)
    {
        if (arg.Compile()()() == null)
        {
            var body1 = (Expression<Func<object>>)arg.Body;
            var body2 = (MemberExpression)body1.Body;
            throw new ArgumentNullException(body2.Member.Name);
        }
    }
}

Used like this:

void F(string foo)
{
    Argument.NotNull(() => () => foo);

The great thing about this is that renaming foo in the IDE will get all the references. (If you have foo in a string, it will get missed.)

If you use this in a tight loop, it may cause performance problems, because it calls .Compile()() each time. You can optimize for performance by adding this overload:

    public static void NotNull(object value, Expression<Func<Func<object>>> arg)
    {
        if (value == null)
        {
            var body1 = (Expression<Func<object>>)arg.Body;
            var body2 = (MemberExpression)body1.Body;
            throw new ArgumentNullException(body2.Member.Name);
        }
    }

Which is used like this:

Argument.NotNull(foo, () => () => foo);

It still gets renames correct, and it saves that call on each iteration.

What I would recommend is using the first version when you write your code, then run it under a profiler, and switch to the second version in the cases that matter.

Jay Bazuzi
It does not appear that this will work for extension methods where atttempting to get the type of "this".
David Williams