Reputation: 180788
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
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
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