3

コードでリフレクションの使用率を最適化しようとしていますが、オブジェクトの複数のプロパティを一度に設定できるかどうか疑問に思っていました。

使用例:

private void SetProperties<T>(List<T> objects, List<Tuple<string, object>> propsAndValues) where T:Task
        {
            Type type = typeof(T);
            var propInfos = propsAndValues.ToDictionary(key => type.GetProperty(key.Item1, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.SetProperty), elem => elem.Item2);

            objects.AsParallel().ForAll(obj =>
                {
                    obj.SetProps(propInfos);                                  
                });

        }

どこ

public static void SetProps<T>(this T obj, Dictionary<PropertyInfo, object> propInfos) where T : Task
        {
            foreach (var propInfo in propInfos)
            {
                propInfo.Key.SetValue(obj, propInfo.Value, null);
            }            
        }

SetProps拡張メソッドをより効率的なものに置き換えたいのですが、まだ適切なものが見つかりません。前もって感謝します ;)

コメントで提供されているリンクを使用してコードを変更しました。通常の方法でも4倍高速です。問題は、これが限界なのか、それとも改善の余地があるのか​​ということです。

class DelegateFactory
{
    public delegate void LateBoundPropertySet(object target, object value);

    public delegate void LateBoundPropertyListSet(object target, List<object> values);

    public static LateBoundPropertySet CreateSetIL(PropertyInfo property)
    {
        var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(object), typeof(object) }, true);
        var gen = method.GetILGenerator();

        var sourceType = property.DeclaringType;
        var setter = property.GetSetMethod(true);

        gen.Emit(OpCodes.Ldarg_0); // Load input to stack
        gen.Emit(OpCodes.Castclass, sourceType); // Cast to source type
        gen.Emit(OpCodes.Ldarg_1); // Load value to stack
        gen.Emit(OpCodes.Unbox_Any, property.PropertyType); // Unbox the value to its proper value type
        gen.Emit(OpCodes.Callvirt, setter); // Call the setter method
        gen.Emit(OpCodes.Ret);

        var result = (LateBoundPropertySet)method.CreateDelegate(typeof(LateBoundPropertySet));

        return result;
    }

    public static LateBoundPropertySet CreateSet(PropertyInfo property)
    {

        var setterType = typeof(Action<,>).MakeGenericType(property.DeclaringType, property.PropertyType);

        var propertyWriter = typeof(PropertyWriter<,>).MakeGenericType(property.DeclaringType, property.PropertyType);

        var setterDelegate = Delegate.CreateDelegate(setterType, property.GetSetMethod());

        var writer = (IPropertyWriter)Activator.CreateInstance(propertyWriter, setterDelegate);

        return writer.SetValue;

    }

    private interface IPropertyWriter
    {
        void SetValue(object instance, object value);
    }

    private interface IPropertyListWriter
    {

        void SetValues(object instance, List<object> values);

    }

    private class PropertyWriter<TInstance, TProperty> : IPropertyWriter
    {

        private readonly Action<TInstance, TProperty> _setValueDelegate;

        public PropertyWriter(Action<TInstance, TProperty> setValueDelegate)
        {

            _setValueDelegate = setValueDelegate;

        }

        public void SetValue(object instance, object value)
        {

            _setValueDelegate((TInstance)instance, (TProperty)value);
        }

    }

}

public static void SetProps2<T>(this T obj, Dictionary<DelegateFactory.LateBoundPropertySet, object> propSetters) where T : Task
    {                        
        foreach (var propSet in propSetters)
        {
            propSet.Key.Invoke(propSet, propSet.Value);
        }
    }
4

2 に答える 2

4

これが本当にボトルネックであるほど十分に反映している場合は、動的コードを調査する価値があるかもしれません。それまでは、おそらくHyperDescriptorコストを削減できるでしょう。非常によく似たコードですが、はるかに安価です。

.NET 4.0以降では、ExpressionAPIを使用して複数のプロパティを設定できますが、これはデリゲートをキャッシュする場合にのみ実際に実行可能です。他の興味深いオプション(同じ制約があります:デリゲートをキャッシュして再利用する必要があります)はDynamicMethodです。ただし、これらのオプションはすべてかなり高度なトピックです。アドバイスさせていただきますが、本当に必要ですか?

于 2010-07-10T09:42:00.490 に答える
1

マークがすでに言ったように、パフォーマンスを向上させるには動的コードを使用する方が良いでしょう。

DynamicMethodアプローチまたはGetSetMethodを使用したDelegate.CreateDelegateのいずれかを選択できます。

DynamicMethodの場合は、次の例を参照してください。DynamicMethodを使用したレイトバウンド呼び出し CreateDelegateについては、次の質問を参照してください。不明なタイプのCreateDelegate

于 2010-07-10T10:00:45.927 に答える