使用字符串访问属性

时间:2010-07-14 17:34:28

标签: c#

给定一个与对象字段名称相同的字符串,如何获取对象字段的引用?

例如,假设我将名为“field1”的字符串传递给GetFieldByStr方法,并且该对象具有字段名称field1,如何获取对field1对象的引用?我假设某种方式使用反射。

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.
   }
}

4 个答案:

答案 0 :(得分:4)

You need to use Reflection

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

(对于属性,请使用PropertyInfo

请注意value是一个对象;为了对它做任何有用的事情,你需要将它强制转换为某个类或接口(或者在C#4中使用dynamic。)

答案 1 :(得分:2)

您可以使用Reflection libraryFieldInfoPropertyInfo取决于您是否需要字段或属性)

示例:

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
}

答案 2 :(得分:2)

这是一个不依赖于反思的想法。缺点是它需要一些设置。您甚至可以定义一些自定义属性,并使用一些聪明的代码在应用程序启动时自动执行设置。

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"));
    }
}

更新:这对我来说似乎很有趣,所以我将一个替代实现集合在一起,它使用属性和扩展方法而不是接口。关于这一点的好处是它每个类只需要很少的代码(你只需要添加属性),并且只有当应用程序实际请求来自特定类的属性时,才会运行设置委托的代码。

我必须赞扬Marc Gravell对this question的答案,了解如何动态创建委托以获取给定PropertyInfo对象的属性。

[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"));
    }
}

答案 3 :(得分:0)

对于属性。

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