非反射不轉換類型地動態Property賦值、取值。


 

適用情況:

為一個不確定的對象動態地為某一個未知的Property或多個 Property 賦值和取值

亮點:

非 Property.GetValue或 Property.SetValue ,使用委托代理緩存機制。

 

因此可以這樣用:

//假設是一個一個Entity對象
var instance = new Topic();
//得到其Property Dictionary
var propDic = new InstancePropertyDictionary(instance);
//無需轉換為Object地賦值
propDic.SetValue("屬性名稱",Int32值或Stirng值...);
//不存在類型轉換地取值
Int32 int32Value = propDic.GetInt32("屬性名稱");
string stringValue = propDic.GetString("屬性名稱");

 

 

以下是全部實現的代碼,單類,可直接使用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Lx
{
/// <summary>
/// Instance的屬性高速讀/寫(無需轉換類型)字典
/// </summary>
class InstancePropertyDictionary
{
/// <summary>
/// Get委托
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
delegate TResult Get<TResult>();

/// <summary>
/// Set委托
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="value"></param>
delegate void Set<TValue>(TValue value);

/// <summary>
/// Instance
/// </summary>
object Target;

/// <summary>
/// Instance類型
/// </summary>
Type TargetType;
public InstancePropertyDictionary(object instance)
{
this.Target = instance;
this.TargetType = Target.GetType();
}

#region Set委托
/// <summary>
/// Key是屬性的名字
/// Value是強類型的委托
/// </summary>
Dictionary<string, Set<Int32>> setInt32Dic = new Dictionary<string, Set<Int32>>();
Dictionary<string, Set<string>> setStringDic = new Dictionary<string, Set<string>>();
#endregion

#region Get委托
Dictionary<string, Get<Int32>> getInt32Dic = new Dictionary<string, Get<Int32>>();
Dictionary<string, Get<string>> getStringDic = new Dictionary<string, Get<string>>();
#endregion

/// <summary>
/// 裝載一個類的屬性
/// </summary>
public void LoadProperty(params string[] names)
{
var props = TargetType.GetProperties();
foreach (var name in names)
{
foreach (var prop in props)
{
if (prop.Name == name)
{
CreateGetSet(prop);
}
}
}
}

/// <summary>
/// 創建屬性的Getter/Setter委托
/// </summary>
/// <param name="property"></param>
void CreateGetSet(PropertyInfo property)
{
string propName = property.Name;
var propType = property.PropertyType;

var propSetMethod = property.GetSetMethod();
var propGetMethod = property.GetGetMethod();
if (typeof(Int32) == propType)
{
var set = CreateSet<Int32>(propSetMethod);
setInt32Dic.Add(propName, set);

var get = CreateGet<Int32>(propGetMethod);
getInt32Dic.Add(propName, get);
}
else if (typeof(string) == propType)
{
var set = CreateSet<string>(propSetMethod);
setStringDic.Add(propName, set);

var get = CreateGet<string>(propGetMethod);
getStringDic.Add(propName, get);
}
//剩下的else if請自己實現
}


Set<T> CreateSet<T>(MethodInfo methodInfo)
{
var result = (Set<T>)Delegate.CreateDelegate(typeof(Set<T>), Target, methodInfo);
return result;
}

Get<T> CreateGet<T>(MethodInfo methodInfo)
{
var result = (Get<T>)Delegate.CreateDelegate(typeof(Get<T>), Target, methodInfo);
return result;
}

/// <summary>
/// Set值
/// </summary>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public void SetValue(string propertyName, Int32 value)
{
//去字典取得強類委托型
var dg = setInt32Dic[propertyName];
dg.Invoke(value);
}

public void SetValue(string propertyName, string value)
{
var dg = setStringDic[propertyName];
dg.Invoke(value);
}

/// <summary>
/// Get值
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
public Int32 GetInt32(string propertyName)
{
var dg = getInt32Dic[propertyName];
return dg.Invoke();
}

public string GetString(string propertyName)
{
var dg = getStringDic[propertyName];
return dg.Invoke();
}

}
}



我不知道Expression Tree是怎么使用的,是否比創建代理委托性能更好,所以貼出來,歡迎跟帖討論。

 

附:

.NET中 Delegate.CreateDelegate方法的實現

[SecuritySafeCritical]
public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!(type is RuntimeType))
{
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "type");
}
RuntimeMethodInfo info = method as RuntimeMethodInfo;
if (info == null)
{
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), "method");
}
Type baseType = type.BaseType;
if ((baseType == null) || (baseType != typeof(MulticastDelegate)))
{
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"), "type");
}
Delegate delegate2 = InternalAlloc(type.TypeHandle.GetRuntimeType());
if (delegate2.BindToMethodInfo(firstArgument, info.MethodHandle.GetMethodInfo(), info.GetDeclaringTypeInternal().TypeHandle.GetRuntimeType(), DelegateBindingFlags.RelaxedSignature))
{
return delegate2;
}
if (throwOnBindFailure)
{
throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTargMeth"));
}
return null;
}

 

我覺得這個類中,影響性能的關鍵就在於  Delegate.CreateDelegate 方法的具體是怎么做的,難道還是Methodinfo.Invoke(object, object[])嗎?

用Reflecter反射發現BindToMethodInfo被標記為 extern了。

 

關於反對本文所說的“非反射”的:

有人回復說,還是用到反射了。

我這里是說 不采用反射的方式去“動態Property賦值、取值”,本文標題也沒有誤導吧?

CreateSet<T>
CreateGet<T>  

這兩個方法的實現可以知道,已經不是在用反射了,而是委托


前面用到了反射的地方,只是去取得Property的GetMethod和SetMethod,然后用來創建強類型的委托。

所以在給Property賦值的時候,是不存在反射的。
而且可以看 Secmoo回復 的測試結果,如果在取值、賦值過程中涉及到了反射機制,是決不會有能超過Expression的性能的。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM