Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#反射:更新属性值的最快方法?_C#_Performance_Reflection_Properties - Fatal编程技术网

C#反射:更新属性值的最快方法?

C#反射:更新属性值的最快方法?,c#,performance,reflection,properties,C#,Performance,Reflection,Properties,这是使用反射更新属性的最快方法吗?假设属性始终为int: PropertyInfo counterPropertyInfo = GetProperty(); int value = (int)counterPropertyInfo.GetValue(this, null); counterPropertyInfo.SetValue(this, value + 1, null); 只需确保以某种方式缓存PropertyInfo,这样就不会重复调用type.GetProperty。除此之外,如果您

这是使用反射更新属性的最快方法吗?假设属性始终为int:

PropertyInfo counterPropertyInfo = GetProperty();
int value = (int)counterPropertyInfo.GetValue(this, null);
counterPropertyInfo.SetValue(this, value + 1, null);

只需确保以某种方式缓存PropertyInfo,这样就不会重复调用type.GetProperty。除此之外,如果您在执行增量的类型上创建一个方法的委托,或者像Teoman建议的那样,让该类型实现一个接口并使用它,可能会更快。

当您知道类型参数时,我做了一些操作(非泛型方法不会有很大不同)<如果无法直接访问属性,则代码>CreateDelegate将是最快的方法。使用
CreateDelegate
可以直接处理
PropertyInfo
GetGetMethod
GetSetMethod
,因此不会每次都使用反射

public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
    return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}

public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
    return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}

// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
    return Delegate.CreateDelegate(typeof(T), method) as T;
}

public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
    var body = propertySelector.Body as MemberExpression;
    if (body == null)
        throw new MissingMemberException("something went wrong");

    return body.Member as PropertyInfo;
}
或者更好的是,您可以将逻辑封装在一个专用类中,以便在其上具有get和set方法

比如:

public class Accessor<S>
{
    public static Accessor<S, T> Create<T>(Expression<Func<S, T>> memberSelector)
    {
        return new GetterSetter<T>(memberSelector);
    }

    public Accessor<S, T> Get<T>(Expression<Func<S, T>> memberSelector)
    {
        return Create(memberSelector);
    }

    public Accessor()
    {

    }

    class GetterSetter<T> : Accessor<S, T>
    {
        public GetterSetter(Expression<Func<S, T>> memberSelector) : base(memberSelector)
        {

        }
    }
}

public class Accessor<S, T> : Accessor<S>
{
    Func<S, T> Getter;
    Action<S, T> Setter;

    public bool IsReadable { get; private set; }
    public bool IsWritable { get; private set; }
    public T this[S instance]
    {
        get
        {
            if (!IsReadable)
                throw new ArgumentException("Property get method not found.");

            return Getter(instance);
        }
        set
        {
            if (!IsWritable)
                throw new ArgumentException("Property set method not found.");

            Setter(instance, value);
        }
    }

    protected Accessor(Expression<Func<S, T>> memberSelector) //access not given to outside world
    {
        var prop = memberSelector.GetPropertyInfo();
        IsReadable = prop.CanRead;
        IsWritable = prop.CanWrite;
        AssignDelegate(IsReadable, ref Getter, prop.GetGetMethod());
        AssignDelegate(IsWritable, ref Setter, prop.GetSetMethod());
    }

    void AssignDelegate<K>(bool assignable, ref K assignee, MethodInfo assignor) where K : class
    {
        if (assignable)
            assignee = assignor.CreateDelegate<K>();
    }
}
公共类访问器
{
公共静态访问器创建(表达式成员选择器)
{
返回新的GetterSetter(memberSelector);
}
公共访问器Get(表达式成员选择器)
{
返回创建(memberSelector);
}
公共存取器()
{
}
类GetterSetter:访问器
{
公共GetterSetter(表达式成员选择器):base(成员选择器)
{
}
}
}
公共类访问器:访问器
{
Func吸气剂;
行动设定者;
公共bool是可读取的{get;private set;}
public bool可写{get;private set;}
这是一个公开的例子
{
得到
{
如果(!IsReadable)
抛出新ArgumentException(“未找到属性获取方法”);
返回Getter(实例);
}
设置
{
如果(!可写)
抛出新ArgumentException(“未找到属性集方法”);
Setter(实例、值);
}
}
受保护的访问器(Expression memberSelector)//未向外部世界提供访问权限
{
var prop=memberSelector.GetPropertyInfo();
IsReadable=prop.CanRead;
iswriteable=prop.CanWrite;
AssignDelegate(IsReadable,ref Getter,prop.getMethod());
AssignDelegate(IsWritable,ref Setter,prop.GetSetMethod());
}
void AssignDelegate(bool assignable,ref K assigner,MethodInfo assignor),其中K:class
{
如果(可转让)
assignee=assignor.CreateDelegate();
}
}
简明扼要。您可以为希望获取/设置的每个“类属性”对携带该类的实例

用法:

Person p = new Person { Age = 23 };
var ageAccessor = Accessor<Person>(x => x.Age);
int age = ageAccessor[p]; //gets 23
ageAccessor[p] = 45; //sets 45
Person p=新人{Age=23};
var ageAccessor=Accessor(x=>x.Age);
int age=ageAccessor[p]//得23分
年龄存取器[p]=45//第45组
这里索引器的使用有点糟糕,您可以用专用的“Get”和“Set”方法来代替它,但对我来说非常直观:)

为了避免每次都必须指定类型

var ageAccessor = Accessor<Person>(x => x.Age);
var nameAccessor = Accessor<Person>(x => x.Name);
var placeAccessor = Accessor<Person>(x => x.Place);
var-ageAccessor=Accessor(x=>x.Age);
var nameAccessor=Accessor(x=>x.Name);
var placeAccessor=Accessor(x=>x.Place);
我将基本
访问器
类设置为可实例化,这意味着您可以

var personAccessor = new Accessor<Person>();
var ageAccessor = personAccessor.Get(x => x.Age);
var nameAccessor = personAccessor.Get(x => x.Name);
var placeAccessor = personAccessor.Get(x => x.Place);
var personAccessor=new Accessor();
var ageAccessor=personacessor.Get(x=>x.Age);
var nameAccessor=personAccessor.Get(x=>x.Name);
var placeAccessor=personAccessor.Get(x=>x.Place);
拥有一个基本的
访问器
类意味着您可以将它们视为一种类型,例如

var personAccessor = new Accessor<Person>();
var personAccessorArray = new Accessor<Person>[] 
                          {
                           personAccessor.Get(x => x.Age), 
                           personAccessor.Get(x => x.Name), 
                           personAccessor.Get(x => x.Place);
                          };
var personAccessor=new Accessor();
var personAccessorArray=新访问器[]
{
PersonalAccessor.Get(x=>x.Age),
personAccessor.Get(x=>x.Name),
personAccessor.Get(x=>x.Place);
};

你应该看看
FastMember
(,]),它与反射相比真的很快

我已经测试了这3种实现:

基准需要一个基准函数:

static long Benchmark(Action action, int iterationCount, bool print = true)
{
    GC.Collect();
    var sw = new Stopwatch();
    action(); // Execute once before

    sw.Start();
    for (var i = 0; i <= iterationCount; i++)
    {
        action();
    }

    sw.Stop();
    if (print) System.Console.WriteLine("Elapsed: {0}ms", sw.ElapsedMilliseconds);
    return sw.ElapsedMilliseconds;
}
一些测试方法:

private static void Set(string propertyName, string value)
{
    var obj = new ClassA();
    obj.PropertyA = value;
}

private static void FastMember(string propertyName, string value)
{
    var obj = new ClassA();
    var type = obj.GetType();
    var accessors = TypeAccessor.Create(type);
    accessors[obj, "PropertyA"] = "PropertyValue";
}

private static void SetValue(string propertyName, string value)
{
    var obj = new ClassA();
    var propertyInfo = obj.GetType().GetProperty(propertyName);
    propertyInfo.SetValue(obj, value);
}

private static void SetMethodInvoke(string propertyName, string value)
{
    var obj = new ClassA();
    var propertyInfo = obj.GetType().GetProperty(propertyName);
    propertyInfo.SetMethod.Invoke(obj, new object[] { value });
}
脚本本身:

var iterationCount = 100000;
var propertyName = "PropertyA";
var value = "PropertyValue";

Benchmark(() => Set(propertyName, value), iterationCount);
Benchmark(() => FastMember(propertyName, value), iterationCount);
Benchmark(() => SetValue(propertyName, value), iterationCount);
Benchmark(() => SetMethodInvoke(propertyName, value), iterationCount);
100000次迭代的结果:

默认设置器:3ms

FastMember:36ms

PropertyInfo.SetValue:109ms

PropertyInfo.SetMethod:91ms


现在您可以选择自己的!!!

我看到您将此作为实例传递。为什么不直接设置属性呢?最快的方法是这样的类实现一个IIncrementable接口并使用它,而不是反射。这太棒了!它非常接近我要找的,但我对所有这些仍然很模糊,我看不到我已经编写了一个通用的ToString方法,可以传递给任何对象,它将返回一个字符串,该字符串由对象的所有公共属性的值组成。它使用PropertyInfo和GetValue来获取每个属性。速度很慢。我想在这里使用您的方法,但似乎我必须知道t的名称他在编译时键入。我没有。我如何调整它?是的,在我的情况下,对象必须键入,而不是泛型对象。但你真的没有类型吗?它们都只是对象吗?如果你真的必须处理对象,那么你将不得不依赖表达式树(我使用CreateDelegate)有中间类型转换之类的,但仍然会非常快。这里显示的内容我不确定我是否能理解您在评论范围内的确切要求,甚至在这里回答您,但如果有必要,您可以提出一个问题。别忘了我在这里通知您,以防万一;)我想你在第一条评论中的链接正是我想要的。我想要一个在复杂时间我不知道其类型的对象的快速getter。非常感谢。如果我只有一个具有完整类名、属性名(如MyNameSpace1.X.Y.Z.ClassName)和PropertyName)的字符串,那么它不能在private p中使用
private static void Set(string propertyName, string value)
{
    var obj = new ClassA();
    obj.PropertyA = value;
}

private static void FastMember(string propertyName, string value)
{
    var obj = new ClassA();
    var type = obj.GetType();
    var accessors = TypeAccessor.Create(type);
    accessors[obj, "PropertyA"] = "PropertyValue";
}

private static void SetValue(string propertyName, string value)
{
    var obj = new ClassA();
    var propertyInfo = obj.GetType().GetProperty(propertyName);
    propertyInfo.SetValue(obj, value);
}

private static void SetMethodInvoke(string propertyName, string value)
{
    var obj = new ClassA();
    var propertyInfo = obj.GetType().GetProperty(propertyName);
    propertyInfo.SetMethod.Invoke(obj, new object[] { value });
}
var iterationCount = 100000;
var propertyName = "PropertyA";
var value = "PropertyValue";

Benchmark(() => Set(propertyName, value), iterationCount);
Benchmark(() => FastMember(propertyName, value), iterationCount);
Benchmark(() => SetValue(propertyName, value), iterationCount);
Benchmark(() => SetMethodInvoke(propertyName, value), iterationCount);