C# 使用反射在我的ViewModel中创建泛型类型命令的缺点是什么?

C# 使用反射在我的ViewModel中创建泛型类型命令的缺点是什么?,c#,wpf,generics,mvvm,command,C#,Wpf,Generics,Mvvm,Command,我有一个数据对象,它有许多不同的列表属性。我想使用一个AddObject命令,而不是为每个列表创建不同的命令,因此产生了以下代码 使用这个有什么缺点吗?我原以为表演可能会很慢,但老实说,我没看到有什么不同 public MyViewModel() { _addCommand = new RelayCommand<IEnumerable>(AddGenericObject); // Old code.... defines an Add command per li

我有一个数据对象,它有许多不同的列表属性。我想使用一个
AddObject
命令,而不是为每个列表创建不同的命令,因此产生了以下代码

使用这个有什么缺点吗?我原以为表演可能会很慢,但老实说,我没看到有什么不同

public MyViewModel()
{ 
    _addCommand = new RelayCommand<IEnumerable>(AddGenericObject);

    // Old code.... defines an Add command per list
    // _addAddressCommand = new RelayCommand(() => AddObject<Address>(AddressList));
    // _addPhoneCommand = new RelayCommand(() => AddObject<Phone>(PhoneList));
    // ... etc
}

private void AddGenericObject(IEnumerable list)
{
    // Find Add Method
    var addMethod = this.GetType()
        .GetMethod("AddObject", BindingFlags.NonPublic | BindingFlags.Instance);

    // Created Generic Add Method
    Type genericType = list.GetType().GetGenericArguments()[0];
    var genericAddMethod = addMethod.MakeGenericMethod(genericType);

    // Invoke Method
    genericAddMethod.Invoke(this, new object[] { list });
}

private void AddObject<T>(EntityCollection<T> list)
   where T : EntityObject, new()
{
    var newItem = new T();
    list.Add(newItem);
}
publicMyViewModel()
{ 
_addCommand=新的RelayCommand(AddGenericObject);
//旧代码…为每个列表定义一个添加命令
//_addAddressCommand=new RelayCommand(()=>AddObject(AddressList));
//_addPhoneCommand=newrelaycommand(()=>AddObject(PhoneList));
//…等等
}
私有void AddGenericObject(IEnumerable列表)
{
//查找添加方法
var addMethod=this.GetType()
.GetMethod(“AddObject”,BindingFlags.NonPublic | BindingFlags.Instance);
//已创建泛型添加方法
类型genericType=list.GetType().GetGenericArguments()[0];
var genericAddMethod=addMethod.MakeGenericMethod(genericType);
//调用方法
Invoke(这个,新对象[]{list});
}
私有void AddObject(EntityCollection列表)
其中T:EntityObject,new()
{
var newItem=newt();
列表。添加(新项);
}
它在XAML中的使用方式如下:

<Button Content="New Address" 
        Command="{Binding AddCommand}"
        CommandParameter="{Binding AddressList}" />

<Button Content="New Phone" 
        Command="{Binding AddCommand}"
        CommandParameter="{Binding PhoneList}" />


一个词是性能,但在您放弃代码基准测试之前,它可能已经足够快了,可以满足您的需要。

在考虑使用反射时,性能始终是最大的因素。一般来说,如果可以的话,你应该尽量避免使用反射。

正如詹姆斯和德罗所建议的,性能是一个重要因素。可以执行以下操作来缓存该方法

    private MethodInfo cachedMethod = null;
    private void AddGenericObject(IEnumerable list)
    {
        if (cachedMethod == null)
        {
            // Find Add Method
            var addMethod = this.GetType()
                 .GetMethod("AddObject", BindingFlags.NonPublic | BindingFlags.Instance);

            // Created Generic Add Method
            var genericType = list.GetType().GetGenericArguments()[0];
            cachedMethod = addMethod.MakeGenericMethod(genericType);
        }

        // Invoke Method
        cachedMethod.Invoke(this, new object[] { list });
    }

我的方法是使用Freezable作为命令对象,将Action(of object)类型的委托作为DependencyProperty,并使用一个转换器,该转换器接受方法名作为ConverterParameter,并将对集合的引用转换为对集合的Add方法的委托(或作为converterparameter使用的任何方法的名称)绑定到集合时。这样,只有在交换绑定的集合对象本身时才会产生反射成本,这应该是相当罕见的,因为您希望保留相同的集合,只需添加和删除项


如果您正在查找示例代码,您可能希望查看以下博文:

如下面的评论所示,性能是反射的一个大问题。请查看使用缓存机制缓存反射结果以加快执行速度。在这种情况下,这是可以的,但它有点脆弱。当列表不是泛型的,或者它包含不同类型的实例?显然,在您自己的代码库中,您可以轻松控制。太糟糕了
ICommand
没有提供源类事件,否则您可以通过附加属性指定目标类型。我喜欢附加属性。它们让我高兴,就像小狗接吻一样。我不瘦k这将起作用,因为该方法需要用许多不同的泛型类型调用,并且只缓存泛型类型方法的一个定义。因为所有类型都将继承IEnumerable,我认为不会。如果我错了,那么您需要做的就是创建一个列表或字典,然后检查是否缓存了该sp特殊类型。我有一个例子,如果你想看的话。