下面是一個不依賴一個想法在反射。缺點是它需要一些設置。您甚至可以定義一些自定義屬性並使用一些巧妙的代碼在應用程序啓動時自動執行設置。
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"));
}
}
attr1是一個字段,而不是您的示例中的屬性。 – Lee 2010-07-14 17:36:05
那麼我將如何使用字符串訪問該字段? – Steve 2010-07-14 17:37:33