2010-07-14 244 views
2

給定與對象字段名稱相同的字符串,如何獲取對象字段的引用?使用字符串訪問屬性

例如,假設我將一個名爲「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. 
    } 
} 
+0

attr1是一個字段,而不是您的示例中的屬性。 – Lee 2010-07-14 17:36:05

+0

那麼我將如何使用字符串訪問該字段? – Steve 2010-07-14 17:37:33

回答

4

You need to use Reflection

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

(有關屬性,使用PropertyInfo

注意value是一個對象;爲了做任何有用的事情,你需要將它轉換爲某個類或接口(或者在C#4中使用dynamic)。

2

您可以用Reflection library(無論是FieldInfoPropertyInfo取決於如果你想有一個字段或屬性)

例這樣做:

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

下面是一個不依賴一個想法在反射。缺點是它需要一些設置。您甚至可以定義一些自定義屬性並使用一些巧妙的代碼在應用程序啓動時自動執行設置。

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

因爲詳細的答案而增加了投票數,並且因爲你的代表積分是「666」 – Steve 2010-07-14 17:55:50

0

對於屬性。

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