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

C# 当存在单个对象的转换方法时,如何创建通用方法来转换对象列表?,c#,generics,C#,Generics,假设某些域和视图对象没有公共基类 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 st

假设某些域和视图对象没有公共基类

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));
}
若已有转换单个对象的方法,那个么可以将域对象列表转换为视图对象列表吗


我觉得我在问这个问题时遗漏了一些关于泛型的非常愚蠢和基本的东西。学习答案总比保持无知要好:

你应该能够使用ConvertAll和ToList函数

ConvertAll允许您投影更改,在您的案例中,这些更改将返回T的IEnumerable,然后ToList将从IEnumerable转换为列表

从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,就像他们从F点到T点一样


您甚至可能不需要ToList

您应该能够使用ConvertAll和ToList功能

ConvertAll允许您投影更改,在您的案例中,这些更改将返回T的IEnumerable,然后ToList将从IEnumerable转换为列表

从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,就像他们从F点到T点一样


如果修改Create函数以在域和视图之间进行映射,您甚至可能不需要ToList

是:

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

如果修改Create函数以在域和视图之间进行映射,则为“是”:

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

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

List<DomainA> domains = GetDomainList();
List<ViewA> views = domains.ConvertAll<ViewA>(x => ViewFactory.Create(x));

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

List<DomainA> domains = GetDomainList();
List<ViewA> views = domains.ConvertAll<ViewA>(x => ViewFactory.Create(x));

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

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

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

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

您不能像正在尝试的那样创建泛型方法。在您的示例中,只有几种方法可以设置T和U,例如Createdomains有意义,但Createints没有意义。泛型方法的调用方决定调用它的类型,因此泛型方法必须适用于任何类型参数,而您的方法不适用


其他人就如何实现您想要的结果给出了一些很好的建议。

您不能像尝试那样创建通用方法。在您的示例中,只有几种方法可以设置T和U,例如Createdomains有意义,但Createints没有意义。泛型方法的调用方决定调用它的类型,因此泛型方法必须适用于任何类型参数,而您的方法不适用


其他人就如何实现你想要的结果给出了一些好的建议。

最终看来,你想要的是一个叫做。不幸的是,我们所有人都没有在C3中实现。如果您想让您的程序自动确定调用哪个方法,您必须使用反射或使用单个分派的虚拟函数

interface IViewFactory<TView, TDomain>
{
   TView Create(TDomain domain);
}

class ViewFactoryA : IViewFactory<ViewA, DomainA>
{
   ...
}
class ViewFactoryB : IViewFactory<ViewB, DomainB>
{
   ...
}

现在,您的初始化代码只需要创建正确的factory对象

最终看来你想要的是一个叫做。不幸的是,我们所有人都没有在C3中实现。如果您想让您的程序自动确定调用哪个方法,您必须使用反射或使用单个分派的虚拟函数

interface IViewFactory<TView, TDomain>
{
   TView Create(TDomain domain);
}

class ViewFactoryA : IViewFactory<ViewA, DomainA>
{
   ...
}
class ViewFactoryB : IViewFactory<ViewB, DomainB>
{
   ...
}

现在,您的初始化代码只需要创建正确的factory对象

我不想弄乱类模型。不过,如果它们有更多的“自定义”功能,您确实可以获得一些优势。或者,如果您想创建一个视图列表,例如,@jeddja,这听起来像是您试图在更适合使用面向对象编程棘轮的地方使用通用编程锤。您已经在概念上与项目相关;让你的两个域类实现接口IViewable{T CreateView;},然后继续。域永远不可能知道这个视图。域在其自己的独立程序集中定义。我也不想让视图知道这个域。这就是为什么我想让第三方承担转换的责任:我意识到我在最初的问题中没有提到这一点;肯定会给出不同的回答。我不想弄乱类模型。不过,如果它们有更多的“自定义”功能,你会得到一些好处。或者,如果您想创建一个视图列表,例如,@jeddja,这听起来像是您试图在更适合使用面向对象编程棘轮的地方使用通用编程锤。您已经在概念上与项目相关;实现两个域类
nt接口IViewable{T CreateView;}并继续。域无法知道该视图。域在其自己的独立程序集中定义。我也不想让视图知道这个域。这就是为什么我想让第三方承担转换的责任:我意识到我在最初的问题中没有提到这一点;我肯定会给出不同的回答。谢谢,这正是我所需要的。实际上,我可以让Func隐式吗?考虑到它总是被称为创建?我不想每次都通过。谢谢,这正是我需要的。我能把函数隐式化吗?考虑到它总是被称为创建?我不想每次都通过考试。