C# 如何重用使用反射获取的属性 private静态字符串生成器(IList obj,字符串propName) { string str=string.Empty; foreach(obj中的var o) { str+=o.GetType().GetProperty(propName).GetValue(o,null); //有没有办法只打一次电话,然后再打电话 //在迭代过程中str=+o.myStrProp? } 返回str; }
是否有一种方法可以重用获取的属性以避免依赖反射为我再次执行此操作。谢谢 你真正想要的是什么 好的,如果您想坚持使用方法签名(C# 如何重用使用反射获取的属性 private静态字符串生成器(IList obj,字符串propName) { string str=string.Empty; foreach(obj中的var o) { str+=o.GetType().GetProperty(propName).GetValue(o,null); //有没有办法只打一次电话,然后再打电话 //在迭代过程中str=+o.myStrProp? } 返回str; },c#,generics,reflection,C#,Generics,Reflection,是否有一种方法可以重用获取的属性以避免依赖反射为我再次执行此操作。谢谢 你真正想要的是什么 好的,如果您想坚持使用方法签名(string:List,string),那么您至少可以像这样重用获取的属性info: private static string GenerateStr<T>(IList<T> obj, string propName) { string str = string.Empty; foreach(var o in obj) {
string
:List
,string
),那么您至少可以像这样重用获取的属性info
:
private static string GenerateStr<T>(IList<T> obj, string propName)
{
string str = string.Empty;
foreach(var o in obj)
{
str += o.GetType().GetProperty(propName).GetValue(o, null);
//is there a way to only call above line once, then call
// str =+ o.myStrProp over the course of the iteration?
}
return str;
}
这应该更快,因为它根本不使用反射。此外,它还可以重写为一行代码;):
这不仅更快,它还通过应用IntelliSense在开发过程中为您提供支持,并避免在有人重构您的财产名称或其他内容时可能会忘记的神奇字符串。您真正需要的
好的,如果您想坚持使用方法签名(string
:List
,string
),那么您至少可以像这样重用获取的属性info
:
private static string GenerateStr<T>(IList<T> obj, string propName)
{
string str = string.Empty;
foreach(var o in obj)
{
str += o.GetType().GetProperty(propName).GetValue(o, null);
//is there a way to only call above line once, then call
// str =+ o.myStrProp over the course of the iteration?
}
return str;
}
这应该更快,因为它根本不使用反射。此外,它还可以重写为一行代码;):
这不仅更快,它还通过应用IntelliSense在开发过程中为您提供支持,并避免在有人重构您的属性名称或其他内容时可能会忘记的神奇字符串。此示例的灵感来自于创建委托,与每次迭代使用的反射相比,它的速度非常快
所以您所要做的就是调用:var accessor=PropertyHelper.CreateAccessor(typeof(T).GetProperty(propName))代码>在循环开始之前。要获取值,只需调用var value=accessor.GetValue(o)代码>
公共静态类属性帮助器
{
公共静态IPropertyAccessor CreateAccessor(PropertyInfo PropertyInfo)
{
如果(propertyInfo==null)
抛出新ArgumentNullException(“propertyInfo”);
return(IPropertyAccessor)Activator.CreateInstance(
typeof(PropertyRapper).MakeGenericType
(propertyInfo.DeclaringType,propertyInfo.PropertyType),propertyInfo);
}
}
公共接口IPropertyValueAccessor
{
PropertyInfo PropertyInfo{get;}
字符串名称{get;}
对象GetValue(对象源);
}
公共接口IPropertyAccessor
{
PropertyInfo PropertyInfo{get;}
字符串名称{get;}
对象GetValue(对象源);
void SetValue(对象源、对象值);
}
内部类PropertyRapper:IPropertyAccessor
{
私有财产信息(不动产信息);;
私有函数方法;
私人行动法;
///
///公共建筑商
///
///原包装
公共财产说话人(财产信息财产信息)
{
_propertyInfo=propertyInfo;
MethodInfo mGet=propertyInfo.GetMethod(true);
MethodInfo mSet=propertyInfo.GetSetMethod(true);
//RQ:关于PUT PAR SE BIAIS AccEDER AUC AUX Access PrimeE
[谚]
//et非chaque appeláGetMethod/SetMethod
_getMethod=(Func)Delegate.CreateDelegate
(功能类型,mGet);
_setMethod=(操作)Delegate.CreateDelegate
(动作类型,mSet);
}
对象IPropertyValueAccessor.GetValue(对象源)
{
返回_getMethod((TObject)源);
}
void IPropertyAccessor.SetValue(对象源,对象值)
{
_setMethod((TObject)源,(TValue)值);
}
///
///瞧
///
公共字符串名
{
得到
{
返回_propertyInfo.Name;
}
}
///
///瞧
///
公共财产信息财产信息
{
得到
{
返回属性信息;
}
}
}
此示例受启发创建了委托,与每次迭代使用的反射相比,它的速度非常快
所以您所要做的就是调用:var accessor=PropertyHelper.CreateAccessor(typeof(T).GetProperty(propName))代码>在循环开始之前。要获取值,只需调用var value=accessor.GetValue(o)代码>
公共静态类属性帮助器
{
公共静态IPropertyAccessor CreateAccessor(PropertyInfo PropertyInfo)
{
如果(propertyInfo==null)
抛出新ArgumentNullException(“propertyInfo”);
return(IPropertyAccessor)Activator.CreateInstance(
typeof(PropertyRapper).MakeGenericType
(propertyInfo.DeclaringType,propertyInfo.PropertyType),propertyInfo);
}
}
公共接口IPropertyValueAccessor
{
PropertyInfo PropertyInfo{get;}
字符串名称{get;}
对象GetValue(对象源);
}
公共接口IPropertyAccessor
{
PropertyInfo PropertyInfo{get;}
字符串名称{get;}
对象GetValue(对象源);
void SetValue(对象源、对象值);
}
内部类PropertyRapper:IPropertyAccessor
{
私有财产信息(不动产信息);;
私有函数方法;
私人行动法;
///
///公共建筑商
///
///原包装
公共财产说话人(财产信息财产信息)
{
_propertyInfo=propertyInfo;
MethodInfo mGet=propertyInfo.GetMethod(true);
MethodInfo mSet=propertyInfo.GetSetMethod(true);
//RQ:关于PUT PAR SE BIAIS AccEDER AUC AUX Access PrimeE
[谚]
//et非chaque appeláGetMethod/SetMethod
_getMethod=(有趣的)
private static string GenerateStr<T>(IEnumerable<T> list, string propName)
{
var propertyInfo = typeof(T).GetProperty(propName);
return string.Concat(list.Select(o => propertyInfo.GetValue(o, null)));
}
private string GenerateStrBetter<T>(IEnumerable<T> list, Func<T, object> func)
{
var res = string.Empty;
foreach (var item in list)
{
res += func(item).ToString();
}
return res;
}
private string GenerateStrBetter<T>(IEnumerable<T> list, Func<T, object> func)
{
return string.Concat(list.Select(item => func(item).ToString()));
}
var result = GenerateStrBetter(list, item => item.Text);
public static class PropertyHelper
{
public static IPropertyAccessor CreateAccessor(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
throw new ArgumentNullException("propertyInfo");
return (IPropertyAccessor)Activator.CreateInstance(
typeof(PropertyWrapper<,>).MakeGenericType
(propertyInfo.DeclaringType, propertyInfo.PropertyType), propertyInfo);
}
}
public interface IPropertyValueAccessor
{
PropertyInfo PropertyInfo { get; }
string Name { get; }
object GetValue(object source);
}
public interface IPropertyAccessor
{
PropertyInfo PropertyInfo { get; }
string Name { get; }
object GetValue(object source);
void SetValue(object source, object value);
}
internal class PropertyWrapper<TObject, TValue> : IPropertyAccessor
{
private PropertyInfo _propertyInfo;
private Func<TObject, TValue> _getMethod;
private Action<TObject, TValue> _setMethod;
/// <summary>
/// Constructeur public
/// </summary>
/// <param name="propertyInfo">la propriété à encapsulé
public PropertyWrapper(PropertyInfo propertyInfo)
{
_propertyInfo = propertyInfo;
MethodInfo mGet = propertyInfo.GetGetMethod(true);
MethodInfo mSet = propertyInfo.GetSetMethod(true);
// Rq : on peut par se biais acceder aussi aux accesseur privé
// tous les aspects liés à la sécurité est donc pris en charge par CreateDelegate
// et non à chaque appel à GetMethod/SetMethod
_getMethod = (Func<TObject, TValue>)Delegate.CreateDelegate
(typeof(Func<TObject, TValue>), mGet);
_setMethod = (Action<TObject, TValue>)Delegate.CreateDelegate
(typeof(Action<TObject, TValue>), mSet);
}
object IPropertyValueAccessor.GetValue(object source)
{
return _getMethod((TObject)source);
}
void IPropertyAccessor.SetValue(object source, object value)
{
_setMethod((TObject)source, (TValue)value);
}
/// <summary>
/// Voir <see cref="IPropertyAccessor.Name">
/// </see></summary>
public string Name
{
get
{
return _propertyInfo.Name;
}
}
/// <summary>
/// Voir <see cref="IPropertyAccessor.PropertyInfo">
/// </see></summary>
public PropertyInfo PropertyInfo
{
get
{
return _propertyInfo;
}
}
}
static string GenerateStrReflection<T>(IList<T> obj, string propName)
{
var property = typeof(T).GetProperty(propName);
return string.Concat(obj.Select(o => property.GetValue(o)));
}
static string GenerateStrExpression<T>(IList<T> obj, string propName)
{
// o
var oParameter = Expression.Parameter(typeof(T), "o");
// o.Property
var propertyExpression = Expression.PropertyOrField(oParameter, propName);
// cast to object ensure we don't get compiler errors when creating the lambda
var cast = Expression.Convert(propertyExpression, typeof(object));
// o => (object)o.Property;
var lambda = Expression.Lambda<Func<T, object>>(cast, oParameter).Compile();
return string.Concat(obj.Select(lambda));
}
static Func<IList<T>, string> GenerateStrExpressionCached<T>(string propName)
{
var oParameter = Expression.Parameter(typeof(T), "o");
var propertyExpression = Expression.PropertyOrField(oParameter, propName);
var cast = Expression.Convert(propertyExpression, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(cast, oParameter).Compile();
// here we return a lambda to operate against the list.
return list => string.Concat(list.Select(lambda));
}
var cachedFunc = GenerateStrExpressionCached<MyClass>("MyProperty");
List<MyClass> myList = ...;
string result = cachedFunc(myList);
List Size Reflection (ms) Expression (ms) Expression Cached (ms)
1 0 127 0
100 20 133 4
10000 2000 600 470
const int ListSize = 10000; //change to what you want to measure
const int Iterations = 1000;
var list = new List<MyClass>(ListSize);
for (var i = 0; i < ListSize; i++)
list.Add(new MyClass());
//initialize the cached function
var cachedFunc = GenerateStrExpressionCached<MyClass>("MyProperty");
var sw = Stopwatch.StartNew();
for (var i = 0; i < Iterations; i++)
GenerateStrExpression(list, "MyProperty");
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
for (var i = 0; i < Iterations; i++)
GenerateStrReflection(list, "MyProperty");
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
for (var i = 0; i < Iterations; i++)
cachedFunc(list);
Console.WriteLine(sw.ElapsedMilliseconds);
...
class MyClass
{
public string MyProperty { get; } = "Hello World";
}