Robert Harvey
Robert Harvey

Reputation: 180788

Calling a property or method using an attribute name

Let's say I have a class that looks like this:

public class CallByAttribute
{
    [CodeName("Foo")]
    public string MyProperty { get; set; }

    [CodeName("Bar")]
    public string MyMethod(int someParameter)
    {
         return myDictionary[someParameter];
    }
}

How would I call these two properties or methods, using CodeName instead of the property or method name?

Upvotes: 4

Views: 6992

Answers (2)

Ani
Ani

Reputation: 113402

Method 1:

public static TOutput GetPropertyByCodeName<TOutput>(this object obj, string codeName)
{
    var property = obj.GetType()
                      .GetProperties()
                      .Where(p => p.IsDefined(typeof(CodeNameAttribute), false))
                      .Single(p => ((CodeNameAttribute)(p.GetCustomAttributes(typeof(CodeNameAttribute), false).First())).Name == codeName);

    return (TOutput)property.GetValue(obj, null);
}

Note: This will throw if no property exists with the specified codeName or if multiple properties share the same codeName.

Usage:

CallByAttribute obj= ...
string myProperty = obj.GetPropertyByCodeName<string>("Foo");

Method 2:

If you are on C# 4, you can write your own System.Dynamic.DynamicObject that can route dynamic calls to the right member.

This will allow for cleaner syntax. For example, you should be able to accomplish something that allows:

CallByAttribute obj= ...
dynamic objectByCodeName = new ObjectByCodeName(obj);
objectByCodeName.Foo = "8";
objectByCodeName.Bar();

Upvotes: 5

Philipp
Philipp

Reputation: 11813

Here's some fully working code including optional call arguments:

    private static string Call(object callByAttribute, string name, object[] args)
    {
        PropertyInfo prop = callByAttribute.GetType().GetProperties()
            .Where(p => p.IsDefined(typeof(CodeNameAttribute), false))
             .SingleOrDefault(p => ((CodeNameAttribute)(p.GetCustomAttributes(typeof(CodeNameAttribute), false)).First()).Name == name);
        if (prop != null)
            return (string)callByAttribute.GetType().InvokeMember(prop.Name, BindingFlags.GetProperty, null, callByAttribute, null);


        MethodInfo method = callByAttribute.GetType().GetMethods()
            .Where(p => p.IsDefined(typeof(CodeNameAttribute), false))
             .SingleOrDefault(p => ((CodeNameAttribute)(p.GetCustomAttributes(typeof(CodeNameAttribute), false)).First()).Name == name);
        if (method != null)
            return (string)callByAttribute.GetType().InvokeMember(method.Name,  BindingFlags.InvokeMethod, null, callByAttribute, args);

        throw new Exception("method/getter not found");
    }
    private static string Call(object callByAttribute, string name)
    {
        return Call(callByAttribute, name, null);
    }

This can be used in a complete program like this:

using System;
using System.Linq;
using System.Reflection;

namespace ConsoleApplication1
{
public class CallByAttribute
{
    [CodeName("Foo")]
    public string MyProperty { get; set; }

    [CodeName("Bar")]
    public string MyMethod(int someParameter)
    {
        return "blah" + someParameter;
    }
}

public class CodeNameAttribute : Attribute
{
    private readonly string name;

    public CodeNameAttribute(string name)
    {
        this.name = name;
    }

    public string Name
    {
        get { return name; }
    }
}


class Program
{
    static void Main(string[] args)
    {
        CallByAttribute callByAttribute = new CallByAttribute();
        callByAttribute.MyProperty = "hi";

        Console.WriteLine(Call(callByAttribute, "Bar", new object[] {1}));
        Console.WriteLine(Call(callByAttribute, "Foo"));

    }
    private static string Call(object callByAttribute, string name)
    {
        return Call(callByAttribute, name, null);
    }


    private static string Call(object callByAttribute, string name, object[] args)
    {
        PropertyInfo prop = callByAttribute.GetType().GetProperties()
            .Where(p => p.IsDefined(typeof(CodeNameAttribute), false))
             .SingleOrDefault(p => ((CodeNameAttribute)(p.GetCustomAttributes(typeof(CodeNameAttribute), false)).First()).Name == name);
        if (prop != null)
            return (string)callByAttribute.GetType().InvokeMember(prop.Name, BindingFlags.GetProperty, null, callByAttribute, null);

        MethodInfo method = callByAttribute.GetType().GetMethods()
            .Where(p => p.IsDefined(typeof(CodeNameAttribute), false))
             .SingleOrDefault(p => ((CodeNameAttribute)(p.GetCustomAttributes(typeof(CodeNameAttribute), false)).First()).Name == name);
        if (method != null)
            return (string)callByAttribute.GetType().InvokeMember(method.Name,  BindingFlags.InvokeMethod, null, callByAttribute, args);

        throw new Exception("method/getter not found");
    }
}
}

Upvotes: 3

Related Questions