使用反射在 ViewModel 中创建通用类型命令有哪些缺点?

发布于 2024-11-29 10:07:07 字数 1403 浏览 2 评论 0原文

我有一个具有许多不同列表属性的数据对象。我想使用单个 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);
}

它在 XAML 中的使用方式如下:

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

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

I have a data object that has many different List properties. I want to use a single AddObject command instead of creating a different command for each List, so came up with the following code.

Is there any downsides you can see to using this? I thought performance might be slow, but I honestly haven't seen a difference.

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);
}

It is used in the XAML by something like this:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜司空 2024-12-06 10:07:07

一言以蔽之 - 性能,但在您摆脱代码基准测试之前 - 它可能足够快以满足您的需求。

In one word - performance, but before you rid of the code benchmark it - it might be fast enough for your needs.

虚拟世界 2024-12-06 10:07:07

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

Performance is always the biggest factor when considering the use of reflection. In general, you should try to avoid using reflection if you can.

叹梦 2024-12-06 10:07:07

正如詹姆斯和德罗所说,表现是一个重要因素。您可以执行以下操作来缓存该方法。

    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 });
    }

Preformance is a big factor as James and Dror have suggested. You can do the following to cache the method.

    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 });
    }
人间不值得 2024-12-06 10:07:07

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

如果您正在寻找示例代码,您可能需要查看此博客文章:http://wpfglue.wordpress.com/2012/05/07/commanding-binding-controls-to-methods/

My way of doing this would be to use a Freezable as Command object, give it a Delegate of type Action(of Object) as a DependencyProperty, and use a converter which accepts a method name as ConverterParameter and converts a reference to the collection into a Delegate to the collection's Add method (or whatever method's name you use as converterparameter) while binding to the collection. This way, the cost of reflection is only incurred when the bound collection object itself is exchanged, which should be fairly rare, since you want to keep the same collection and just add and remove items.

If you are looking for example code, you might want to check out this blog post: http://wpfglue.wordpress.com/2012/05/07/commanding-binding-controls-to-methods/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文