将一个列表的内容复制到另一个不同类型的列表

时间:2018-03-02 22:39:15

标签: c# list ienumerable ienumerator

我无法将List<TemplateSection>的内容复制到List<Section>。这些定义如下:

List<TemplateSection>

public class TemplateSection
{
    public string SectionName { get; set; }
    public List<MyTemplateItem> MyTemplateItems { get; set; }
}

public class MyTemplateItem
{
        public string ItemName { get; set; }
        public string ItemText { get; set; }
}

List<Section>是:

public class Section
{
    public string SectionName { get; set; }
    public List<MyItem> MyItems { get; set; }
}
public class MyItem
{
    public string ItemName { get; set; }
    public string ItemText { get; set; }
    public string ItemValue { get; set; }
}

ItemValue在复制时不需要值,或者它可能只是一个空字符串。

List<TemplateSection>是每个部分中的部分和复选框项目列表,每个复选框都有唯一的名称。 List<Section>是用户进行更新时从表单中保存的值。

我尝试过:List<Section> listSection = listTemplateSection.Cast<Section>().ToList();但它无法投射。

除了在这里提供定义之外,我不知道如何描述这一点。请帮忙!

2 个答案:

答案 0 :(得分:1)

编译器无法猜测如何从TemplateSection转换为Section。你必须自己明确地做:

var ans = myTemplateSelections.Select(aTemplate => new Section {
        SectionName = aTemplate.SectionName,
        MyItems = aTemplate.MyTemplateItems.Select(ti => new MyItem {
            ItemName = ti.ItemName,
            ItemText = ti.ItemText //,
            // ItemValue = ???
        }).ToList();
    };

根据几条评论,如果您愿意编写自己的转换运算符,则可以使用Cast

更改模板类以包含转换运算符:

public class TemplateSection {
    public string SectionName { get; set; }
    public List<MyTemplateItem> MyTemplateItems { get; set; }

    public static explicit operator Section(TemplateSection src) {
        return new Section {
            SectionName = src.SectionName,
            MyItems = new List<MyItem>(src.MyTemplateItems.Cast<MyItem>())
        };
    }
}

public class MyTemplateItem {
    public string ItemName { get; set; }
    public string ItemText { get; set; }

    public static explicit operator MyItem(MyTemplateItem src) {
        return new MyItem {
            ItemName = src.ItemName,
            ItemText = src.ItemText
        };
    }
}

然后您可以使用Cast

var sections = new List<Section>(myTemplateSections.Cast<Section>());

答案 1 :(得分:1)

C#没有像你期望的那样提供duck typing(它看起来一样,所以我应该能够施展它)。此外,C#仅允许covariance限制接口和委托,这使您的用例变得复杂。并且List<T>也不是(IReadOnlyList)的协变,因此增加了更多的复杂性。通过继承,协方差和接口,您可以执行此操作:

class Program
{

    static void Main(string[] args)
    {
        var list = new List<MySection>();

        list.Add(new MySection()
        {
            Items = new List<MyItem>()
            {
                new MyItem() { Name = "One", Text = "Two", Value = "Three" }
            }
        });

        // can access value here: list.First().Items.First().Value

        IEnumerable<ISection<TemplateItem>> genericList = list;

        foreach (ISection<TemplateItem> genericSection in genericList) 
        {
            // no value here
        }
    }

}

public interface ISection<out T> where T : TemplateItem
{

    string Name { get; }

    IEnumerable<T> Items { get; }

}

public class TemplateSection<T> : ISection<T> where T : TemplateItem
{

    public string Name { get; set; }

    public List<T> Items { get; set; }

    IEnumerable<T> ISection<T>.Items => Items;
}

public class TemplateItem
{
    public string Name { get; set; }
    public string Text { get; set; }
}

public class MySection : TemplateSection<MyItem>
{        

}

public class MyItem : TemplateItem
{
    public string Value { get; set; }
}

协变IEnumerable(定义为out T)允许我们将MySection分配给ISection<T>中的IEnumerable。我想,不过会有更优雅的方式。