代码之家  ›  专栏  ›  技术社区  ›  Steve

使用字符串访问属性

c#
  •  2
  • Steve  · 技术社区  · 15 年前

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

    例如,假设我将一个名为“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 回复  |  直到 15 年前
        1
  •  4
  •   SLaks    15 年前

    You need to use Reflection :

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

    (对于属性,请使用 PropertyInfo

    请注意 value dynamic 在C#4)。

        2
  •  3
  •   Community Mohan Dere    8 年前

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

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

    更新:这对我来说似乎很有趣,所以我创建了一个替代实现,它使用属性和扩展方法,而不是接口。这样做的好处是,每个类只需要很少的代码(您只需要添加属性),而设置委托的代码仅在应用程序实际从特定类请求属性时运行。

    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
  •  2
  •   mbillard    15 年前

    你可以用 Reflection library FieldInfo PropertyInfo (取决于您想要的是字段还是属性)

    例子:

    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
    }
    
        4
  •  0
  •   George Johnston    15 年前

    对于属性。

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