使用Linq c#将List<A>转换为List<B>

5

如何将我的“Person”类型列表(由我的数据库创建)转换为“myPerson”类型,而不出现错误。

我尝试过这样做:

DataClasses1DataContext d = new 
DataClasses1DataContext(MainWindow.mySqlClass.GetConnection());

var query = from pers in d.Person select pers;

personen = query.ToList();
newPerson = personen.Cast<myPerson>().ToList();

但我只收到一个“System.InvalidCastException”错误。
public partial class myPerson : Person
{
    public override string ToString()
    {
        return Name + " " + Nachname;
    }
    public myPerson(System.Data.Linq.EntitySet<Bilder> bilder, string geschlecht, int iD, string nachname, string name)
    {
        Bilder = bilder;
        Geschlecht = geschlecht;
        ID = iD;
        Nachname = nachname;
        Name = name;
    }
}

Linq创建的类(仅列出前几行):
public partial class Person : INotifyPropertyChanging, INotifyPropertyChanged
{

    private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

    private int _ID;

    private string _Nachname;

    private string _Name;

    private string _Geschlecht;

    private EntitySet<Bilder> _Bilder;

有没有人知道如何将类型为Person的List转换为类型为myPerson的List?

还是说有没有办法创建一个“查询”,可以将Person转换为myPerson?


5
你需要在MyPerson类中添加一个接受Person实例的构造函数,然后使用Select(x => new MyPerson(x))代替Cast<MyPerson>() - MakePeaceGreatAgain
我该怎么做呢? 我是C#的新手。 - newbie
2
我看到你从 Person 派生了 myPerson(应该是 MyPerson)。我建议改用一个接口 IPerson,两者都实现,并在 MyPerson 中有一个 Person 字段,这样你就不必不必要地复制东西了。(参见“组合优于继承”) - Fildor
@Fildor 我需要复制这个列表,因为第一个列表可能会在运行时更改,最终我想将第一个列表与第二个列表进行比较,看哪些值已更改,哪些值未更改。 - newbie
为什么不直接使用 Select 呢?强制类型转换并不会自动映射任何内容,它只是将对象转换为另一种类型,也就是允许您将相同的对象视为另一种兼容类型。如果这不可能,它就会抛出异常。 - Panagiotis Kanavos
显示剩余3条评论
4个回答

6
每个 myPerson 实例都可以转换为 Person,因为 myPerson 类继承自 Person。但是你不能反过来,将一个 Person 转换为 myPerson(即从父类向子类转换)。只有在它确实是 myPerson 的情况下,你才能这样做,但在这种情况下,转换会失败。
如果你有一个 Person 并想将其转换为 myPerson,你应该提供一个接受 Person 实例并初始化(或返回)myPerson 实例的构造函数(或工厂方法)。
public partial class myPerson : Person
{
    public myPerson(Person p)
    {
        _ID = p.Id;
        _Nachname = p.Nachname;
        _Name = p.Name;
        _Geschlecht = p.Geschlecht;
        _Bilder = p.Bilder;
    }

    private int _ID;
    private string _Nachname;
    private string _Name;
    private string _Geschlecht;
    private EntitySet<Bilder> _Bilder;
    // add properties
}

那么您可以使用:

personen = query.ToList();
newPerson = personen.Select(p => new myPerson(p)).ToList();

我相信 OP 实际上只想要对列表进行深度复制。请参见问题下的评论:“我需要复制该列表,因为第一个列表可能会在运行时更改,最终我想将第一个列表与第二个列表进行比较,看哪些值已更改,哪些未更改。” - Fildor
@Fildor:那我就不明白了。每当他向数据库请求当前的“人员”时,他都会得到一个新的列表,其中包含新的“人员”实例,他可以将其与旧的实例进行比较。 - Tim Schmelter
不确定是否意识到这一点...对我来说,他似乎是一个初学者。对我来说,这很像x-y。 - Fildor

2
var query = from pers in d.Person 
            select new myPerson 
                  {
                     Name = pers.Name,
                     ...
                  } ;

将省略号(...)替换为您想要映射的其他属性。

0

也许this StackOverflow 可以解决你的问题?

这里是 Botz3000 的被采纳的答案

ChildClassList = BaseClassList.Cast<ChildClass>().ToList();

你目前的代码在无法将BaseClass项目转换为ChildClass时添加了null。 如果这确实是您的意图,那么这将是等效的:

ChildClassList = BaseClassList.Select(x => x as ChildClass).ToList();

但我更倾向于建议这个,它包括类型检查并将跳过不匹配的项:

ChildClassList = BaseClassList.OfType<ChildClass>().ToList();

"


0

无论是否使用实体框架,都不能将一个类集合转换为子类集合。

您需要创建一个新的集合,在这种情况下是一个新的列表,并用您创建的新对象填充它。您可以在linq中使用select来完成这个操作,如下所示:

d.Person.Select(x => new myPerson(....)).ToList();

这将遍历所有Person实例,为每个实例创建一个新的myPerson,并将结果转换为List。

不要直接编写... - 您需要根据myPerson的ctor定义来执行此操作,将Person的所有字段复制到myPerson中,例如:

new myPerson(x.Bilder, x.Geschlecht, .......

或者按照注释所说,为myPerson创建一个构造函数,该构造函数接受一个Person对象作为参数,然后在构造函数内部复制您需要的字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接