对象初始化器

本文关键字:初始化 对象 | 更新日期: 2023-09-27 17:50:32

这两个代码片段都可以工作,但是,我想知道哪一个更好(如果有的话)。真的有区别吗?我所指的代码部分在LINQ中。如有任何见地,不胜感激。

select new Product {...

第一个片段:

public static IEnumerable<Product> GetProducts(IEnumerable<Product> products)
{
    var query = from p in products
                select new Product
                {
                    Category = p.Category,
                    Id = p.Id,
                    CategoryId = p.CategoryId,
                    Name = p.Name
                };
    return query;
}

class Product
{
    public int Id { get; set; }
    public String Name { get; set; }
    public Category Category { get; set; }
    public int CategoryId { get; set; }
}
class Category
{
    public int Id { get; set; }
    public String CategoryName { get; set; }
} 

第二个片段:

 public static IEnumerable<Product> GetProducts(IEnumerable<Product> products)
    {
        var query = from p in products
                    select p;
        return query;
    }

class Product
{
    public int Id { get; set; }
    public String Name { get; set; }
    public Category Category { get; set; }
    public int CategoryId { get; set; }
}
class Category
{
    public int Id { get; set; }
    public String CategoryName { get; set; }
}

对象初始化器

第一个代码片段将返回一个查询,当枚举时,该查询将创建products可枚举对象中每个对象的副本,并遍历这些副本。(注意:如果输入对象的类型来源于Product而不是Product本身,那么您将把这些对象"切片"到Product的实例中。)

第二个代码片段将返回一个查询,该查询在枚举时将按原始顺序遍历对象,并且在语义上与return products;没有什么不同(假设products不为空,也就是说——如果products为空,则枚举时这两种变体都会抛出异常,但会抛出不同的异常类型)。

"tl;dr"版本是:第一种方法复制序列中的对象,第二种方法不复制。

当您需要对序列进行深度复制时,使用第一个,以便修改结果序列中的对象不会修改原始序列中的对象。如果您确实希望修改影响原始序列,则使用第二种方法,您将不会修改两个序列中的任何一个。


旁白:如果您确实需要获取副本,请考虑在Product类(public virtual Product Clone())上创建一个虚拟方法,以便(a)封装克隆逻辑,(b)如果派生Product,则可以覆盖Clone()以返回正确类型的副本。