代码之家  ›  专栏  ›  技术社区  ›  Jedidja

当存在单个对象的转换方法时,如何创建通用方法来转换对象列表?

  •  1
  • Jedidja  · 技术社区  · 16 年前

    假设一些域和视图对象(没有公共基类)

    public class DomainA
    {
        public int MyProperty { get; set; }
    }
    
    public class ViewA
    {
        public int MyProperty { get; set; }
    }
    
    public class DomainB
    {
        public string MyProperty { get; set; }
    }
    
    public class ViewB
    {
        public string MyProperty { get; set; }
    }
    

    以及一个可以从域转换为相应视图的类

    public class ViewFactory
    {
        public static ViewA Create(DomainA value)
        {
            return new ViewA() { MyProperty = value.MyProperty };
        }
    
        public static ViewB Create(DomainB value)
        {
            return new ViewB() { MyProperty = value.MyProperty };
        }
    }
    

    是否可以按照

    public static List<T> Create<T, U>(IEnumerable<U> values)
    {
        return new List<T>(from v in values where v != null select Create((U)v));
    }
    

    它可以将“域”对象的列表转换为“视图”对象的列表,前提是已经有了转换单个对象的方法?

    我觉得我遗漏了泛型的一些非常愚蠢和基本的东西,比如问这个问题..与其无所事事,不如学会答案:)

    6 回复  |  直到 16 年前
        1
  •  2
  •   Lee    16 年前

    如果修改create函数以在域和视图之间进行映射,则为yes:

    public static List<T> Create<T, U>(IEnumerable<U> values, Func<U, T> mapFunc)
    {
        return values.Select(v => mapFunc(v)).ToList();
    }
    

    然后可以使用viewfactory方法进行映射:

    IEnumerable<DomainA> domAs = //whatever
    var aViews = Create(domAs, a => ViewFactory.Create(a));
    
        2
  •  2
  •   Kev Hunter    16 年前

    您应该能够使用convertall和tolist函数

    convertall允许您投影更改,在您的情况下,这些更改将返回IEnumerable of T,然后ToList将从IEnumerable转换为List

    从msdn的文章里偷来的

           List<PointF> lpf = new List<PointF>();
    
        lpf.Add(new PointF(27.8F, 32.62F));
        lpf.Add(new PointF(99.3F, 147.273F));
        lpf.Add(new PointF(7.5F, 1412.2F));
    
        Console.WriteLine();
        foreach( PointF p in lpf )
        {
            Console.WriteLine(p);
        }
    
        List<Point> lp = lpf.ConvertAll( 
            new Converter<PointF, Point>(PointFToPoint));
    
        Console.WriteLine();
        foreach( Point p in lp )
        {
            Console.WriteLine(p);
        }
    

    你应该能从U到T,就像他们从一个点到另一个点一样

    你甚至不需要收费员

        3
  •  2
  •   Matt Dearing    16 年前

    您不应该需要自定义方法来创建列表。您只需执行以下操作:

    List<DomainA> domains = GetDomainList();
    List<ViewA> views = domains.ConvertAll<ViewA>(x => ViewFactory.Create(x));
    
        4
  •  1
  •   Fiona - myaccessible.website    16 年前

    嗯,在我看来,你需要一个更面向对象的模型,而不是泛型:

    public abstract class Domain
    {
        public abstract View CreateView();
    }
    
    public abstract class View
    {
    }
    
    public class DomainA : Domain
    { 
        public int MyProperty { get; set; } 
    
        public override View CreateView()
        {   
            return new ViewA() { MyProperty = value.MyProperty }; 
        }
    } 
    
    public class ViewA : View
    { 
        public int MyProperty { get; set; } 
    } 
    
    public class DomainB : Domain
    { 
        public string MyProperty { get; set; } 
    
        public override View CreateView()
        {   
            return new ViewB() { MyProperty = value.MyProperty }; 
        }
    } 
    
    public class ViewB : View
    { 
        public string MyProperty { get; set; } 
    } 
    
        5
  •  1
  •   kvb    16 年前

    不能像您试图创建的那样创建泛型方法。在您的示例中,只有几种方法可以设置 T U 会起作用的(例如 Create<ViewA,DomainA>(domains) 很有意义,但是 Create<string,int>(ints) 不会)。泛型方法的调用方决定调用它的类型,因此泛型方法必须适用于任何类型参数,而您的方法不适用于任何类型参数。

    其他人对如何达到你想要的结果给出了好的建议。

        6
  •  0
  •   Robert Davis    16 年前

    最终看起来你想要的是一个叫做 multiple dispatch . 不幸的是,我们所有人都没有在C 3中实现。如果你想让你的程序自动计算出要调用哪个方法,你就必须使用反射或者使用一个虚拟函数使用单个分派。

    interface IViewFactory<TView, TDomain>
    {
       TView Create(TDomain domain);
    }
    
    class ViewFactoryA : IViewFactory<ViewA, DomainA>
    {
       ...
    }
    class ViewFactoryB : IViewFactory<ViewB, DomainB>
    {
       ...
    }
    

    现在,初始化代码只需要创建正确的工厂对象。