首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >关于使用这种继承的泛型方法的建议

关于使用这种继承的泛型方法的建议
EN

Stack Overflow用户
提问于 2010-03-19 21:43:34
回答 2查看 173关注 0票数 4

我们继承了一个项目,它是核心业务模型一部分的包装器。

有一种方法采用泛型,从成员中查找匹配该类型的项,然后返回该类型的列表。

代码语言:javascript
复制
public List<T> GetFoos<T>()
{
    List<IFoo> matches = Foos.FindAll(
        f => f.GetType() == typeof(T)
    );

    List<T> resultList = new List<T>();
    foreach (var match in matches)
    {
        resultList.Add((T)obj);
    }
}

Foos可以将相同的对象保存在继承层次结构中的不同类中,以对不同的UI表示进行不同的汇总。20+有不同类型的后代,可以由GetFoos返回。

现有的代码基本上有一个大开关语句,在整个代码中复制和粘贴。每个部分中的代码以其相应的类型调用GetFoos。

我们目前正在将其重构为一个合并区域,但在我们所做的工作中,我们正在考虑使用该方法的其他方法。

其中一个想法是使用反射传递类型,这非常有效,直到我们实现了调用返回一个对象,并且需要以某种方式将其转换到列表中。

另一种方法是只使用开关语句,直到4.0,然后使用动态语言选项。

我们欢迎关于如何使用这种方法的任何其他想法。我留下的代码非常简短,但如果您想知道任何其他细节,请直接问。

更新

switch语句最初使用的是字符串,第一次传递是将它移动到演示器中,其内容如下:(不对开关进行重构,只需要数据)。

代码语言:javascript
复制
// called on an event handler in FooPresenter
// view is the interface for the ASPX page injected into FooPresenter's constructor
// wrapper is the instance of the model wrapper that has the GetFoos method
// selectedFooName is the value of a DropDownList in the Page
//  letting the user say how they want to see the animals
//   its either one big group (Animal)
//   or individual types (Tiger, Lion)
private void LoadFoos(string selectedFooName)
{
    switch (selectedFooName)
    {
        case "Animal":  // abstract base class for all other types
            this.view.SetData(this.wrapper.GetFoos<Animal>(); 

        case "Lion":
            this.view.SetData(this.wrapper.GetFoos<Lion>();
            break;

        case "Tiger":
            this.view.SetData(this.wrapper.GetFoos<Tiger>();    
            break;

        case "Bear":
            this.view.SetData(this.wrapper.GetFoos<Bear>();
            break;    
    }
}

视图实现( ASPX页面的代码隐藏)

代码语言:javascript
复制
public void SetData<T>(List<T> data)
{
    // there is a multiview on the page that contains user controls with 
    // grid layouts for the different types

    // there is a control for the common type of "Animal"
    // and other controls for Tiger, Bear, etc

    // the controls contain a 3rd party grid of pain 
    // and the grids' binding event handlers cast the data item 
    // for the row and do some stuff with it specific to that type
}

我们的第一个步骤是至少在开关语句中使用Type,或者添加一个enum。

我一直在使用策略模式,但当我到达加载工厂时,我不得不停下来,再次返回列表,并意识到我没有这个类型。

EN

回答 2

Stack Overflow用户

发布于 2010-03-19 21:50:00

不看到调用GetFoos()的代码是很困难的..。如果您可以显示更多描述如何调用它的代码,我们可以建议如何重构它。

听起来,解决方案也是将调用例程变成一个泛型例程--这样它就可以通过只使用一个泛型类型(根据需要指定)来避免20种类型的“开关”。然而,这可能是不可行的,但同样,如果没有代码,很难知道.

话虽如此,您可以重构GetFoos,使其更加简单:

代码语言:javascript
复制
public List<T> GetFoos<T>()
{
    return Foos.OfType<T>().ToList();
}

编辑:正如Eric所指出的,上面的代码返回任何类型的T,但也返回T的子类,尽管这很可能是实际需要的行为,但与原始代码不同。如果由于某些原因而不希望这样做,则可以使用:

代码语言:javascript
复制
public List<T> GetFoos<T>()
{
    Type type = typeof(T);
    return Foos.Where(item => item.GetType() == type).ToList();
}

这将具有与原始代码相同的行为。

票数 2
EN

Stack Overflow用户

发布于 2010-03-19 22:08:16

像这样吗?

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SO_2480770 {
    interface IFoo {}
    class MyBase : IFoo {}
    class Bar : MyBase {}

    class Program {               
        IEnumerable<IFoo> Foos { get; set; }

        static void Main(string[] args) {           
            List<MyBase> bases = new List<MyBase>() { new MyBase(), new MyBase() };
            List<Bar> bars = new List<Bar>() { new Bar(), new Bar() };            
            Program p = new Program();
            p.Foos = bases.Concat(bars);            
            var barsFromFoos = p.GetFoos<Bar>();
            var basesFromFoos = p.GetFoos<MyBase>();
            Debug.Assert(barsFromFoos.SequenceEqual(bars));
            Debug.Assert(basesFromFoos.SequenceEqual(bases.Concat(bars)));
            Debug.Assert(!barsFromFoos.SequenceEqual(bases));
            Console.ReadLine();
        }               

        public List<T> GetFoos<T>() where T : IFoo {            
            return Foos.OfType<T>().ToList();
        }
    }    
}

要摆脱大开关语句,要么必须进一步推升泛型。也就是说,使具有switch语句的方法接受一个泛型类型参数,并继续进行,直到在必须的情况下,您无法进一步执行调用链。当这变得太困难时,考虑一下抽象工厂、工厂、模板方法等设计模式。这取决于调用代码的复杂程度。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2480770

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档