开发者

Access to Attributes using a String

Given a string with the same name of an object field, how can I get the reference to the object field?

For example, say I pa开发者_开发知识库ss in a string called "field1" to the GetFieldByStr method, and the object has an field name field1, how can I get a reference to the field1 object? I'm assuming using reflection somehow.

class Example {
   private FieldExample attr1;

   void GetFieldByStr(String str) {
      // We get passed in "field1" as a string, now I want 
      // to get the field1 attribute.
   }
}


You need to use Reflection:

FieldInfo field = typeof(Example).GetField(str);
object value = field.GetValue(this);

(For properties, use PropertyInfo)

Note that value is an object; in order to do anything useful with it, you'll need to cast it to some class or interface (or use dynamic in C# 4).


Here's an idea that doesn't rely on reflection. The downside is that it requires some setup. You could possibly even define some custom attributes and use some clever code to perform the setup automatically on application start.

interface IAttributeStore
{
    T GetAttribute<T>(string key);
}

class Example : IAttributeStore
{
    public int ExampleID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    static Dictionary<string, Delegate> _AttributeAccessors;

    static Example()
    {
        _AttributeAccessors = new Dictionary<string, Delegate>();

        _AttributeAccessors.Add("ExampleID", new Func<Example, int>((example) => example.ExampleID));
        _AttributeAccessors.Add("FirstName", new Func<Example, string>((example) => example.FirstName));
        _AttributeAccessors.Add("LastName", new Func<Example, string>((example) => example.LastName));
    }

    #region IAttributeStore Members

    public T GetAttribute<T>(string key)
    {
        Delegate accessor;
        if (_AttributeAccessors.TryGetValue(key, out accessor))
        {
            Func<Example, T> func = accessor as Func<Example, T>;
            if (func != null)
                return func(this);
            else
                throw new Exception(string.Format("The attribute with the given key \"{0}\" is not of type [{1}].", key, typeof(T).FullName));
        }
        else
        {
            throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\".", key), "key");
        }
    }

    #endregion
}

class Program
{
    static void Main(string[] args)
    {
        Example example = new Example() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };

        Console.WriteLine(example.GetAttribute<int>("ExampleID"));
        Console.WriteLine(example.GetAttribute<string>("FirstName"));
        Console.WriteLine(example.GetAttribute<string>("LastName"));
    }
}

Update: This seemed interesting to me, so I threw together an alternative implementation that utilizes attributes and extension methods instead of an interface. The nice thing about this is that it requires very little code per class (you just need to add the attributes), and the code that sets up the delegates only runs if the application actually requests an attribute from a particular class.

I have to give credit to Marc Gravell's answer to this question for how to dynamically create a delegate for getting a property given a PropertyInfo object.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
class AttributeStoreAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
class StoredAttributeAttribute : Attribute
{
    public string Key { get; set; }
}

public static class AttributeStore<T>
{
    static Dictionary<string, Delegate> _AttributeAccessors;

    public static void Initialize()
    {
        _AttributeAccessors = new Dictionary<string, Delegate>();

        Type type = typeof(T);

        // let's keep it simple and just do properties for now
        foreach (var property in type.GetProperties())
        {
            var attributes = property.GetCustomAttributes(typeof(StoredAttributeAttribute), true);
            if (attributes != null && attributes.Length > 0)
            {
                foreach (object objAttribute in attributes)
                {
                    StoredAttributeAttribute attribute = objAttribute as StoredAttributeAttribute;
                    if (attribute != null)
                    {
                        string key = attribute.Key;

                        // use the property name by default
                        if (string.IsNullOrEmpty(key))
                            key = property.Name;

                        if (_AttributeAccessors.ContainsKey(key))
                            throw new Exception(string.Format("An attribute accessor has already been defined for the given key \"{0}\".", key));

                        Type typeOfFunc = typeof(Func<,>).MakeGenericType(type, property.PropertyType);
                        Delegate accessor = Delegate.CreateDelegate(typeOfFunc, null, property.GetGetMethod());
                        _AttributeAccessors.Add(key, accessor);
                    }
                }
            }
        }
    }

    public static object GetAttribute(T store, string key)
    {
        if (_AttributeAccessors == null)
            Initialize();

        Delegate accessor;
        if (_AttributeAccessors.TryGetValue(key, out accessor))
        {
            return accessor.DynamicInvoke(store);
        }
        else
        {
            throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\" on attribute store [{1}].", key, typeof(T).FullName), "key");
        }
    }

    public static TResult GetAttribute<TResult>(T store, string key)
    {
        if (_AttributeAccessors == null)
            Initialize();

        Delegate accessor;
        if (_AttributeAccessors.TryGetValue(key, out accessor))
        {
            Func<T, TResult> func = accessor as Func<T, TResult>;
            if (func != null)
                return func(store);
            else
                throw new Exception(string.Format("The attribute with the given key \"{0}\" on attribute store [{1}] is not of type [{2}].", key, typeof(T).FullName, typeof(TResult).FullName));
        }
        else
        {
            throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\" on attribute store [{1}].", key, typeof(T).FullName), "key");
        }
    }
}

public static class AttributeStoreExtensions
{
    public static object GetAttribute<T>(this T store, string key)
    {
        return AttributeStore<T>.GetAttribute(store, key);
    }

    public static TResult GetAttribute<T, TResult>(this T store, string key)
    {
        return AttributeStore<T>.GetAttribute<TResult>(store, key);
    }
}

[AttributeStore]
class Example
{
    [StoredAttribute]
    public int ExampleID { get; set; }

    [StoredAttribute]
    public string FirstName { get; set; }

    [StoredAttribute]
    public string LastName { get; set; }
}

[AttributeStore]
class Example2
{
    [StoredAttribute]
    [StoredAttribute(Key = "ID")]
    public int ExampleID { get; set; }

    [StoredAttribute]
    [StoredAttribute(Key = "First")]
    public string FirstName { get; set; }

    [StoredAttribute]
    [StoredAttribute(Key = "Last")]
    public string LastName { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Example example = new Example() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };

        Console.WriteLine(example.GetAttribute("ExampleID"));
        Console.WriteLine(example.GetAttribute("FirstName"));
        Console.WriteLine(example.GetAttribute("LastName"));

        Example2 example2 = new Example2() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };

        // access attributes by the default key (property name)
        Console.WriteLine(example2.GetAttribute("ExampleID"));
        Console.WriteLine(example2.GetAttribute("FirstName"));
        Console.WriteLine(example2.GetAttribute("LastName"));

        // access attributes by the explicitly specified key
        Console.WriteLine(example2.GetAttribute("ID"));
        Console.WriteLine(example2.GetAttribute("First"));
        Console.WriteLine(example2.GetAttribute("Last"));
    }
}


You can do so with the Reflection library (either FieldInfo or PropertyInfo depending if you want a field or a property)

Example:

void GetAttributesByStr(String str) {
    FieldInfo attributeInfo = this.GetType().GetField(str); // you might want to use some Binding flags here like BindingFlags.Instance and BindingFlags.Public

    attributeInfo.GetValue(this); // assign this to something or return it as an object
}


For properties.

var prop = this.GetType().GetProperty(str);
prop.GetValue(prop, null);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜