简体   繁体   English

如何将“类列表”转换为“其接口列表”?

[英]How to cast a 'list of classes' to a 'list of its interface'?

I need to cast a class list to its own interface list. 我需要将一个类列表转换为它自己的接口列表。

So I have interface Demo_Interface and two classes based on Demo_Interface , Now I create list of classes like List<Test_Class1> 所以我有接口Demo_Interface和两个基于Demo_Interface类,现在我创建类列表,如List<Test_Class1>

And I have a function with List<Demo_Interface> parameter. 我有一个带有List<Demo_Interface>参数的函数。

Here's interface : 这是界面:

       interface Demo_Interface
        {
            int test_int { get; set; }
        }

Here's Entire Code : 这是整个代码:

using System;
using System.Collections.Generic;

namespace ConsoleApp3
{
    class Program
    {
        ///// Main Interface
        interface Demo_Interface
        {
            int test_int { get; set; }
        }

        //// Class 1 Based On Demo_Interface
        class Test_Class1 : Demo_Interface
        {
            public int test_int { get; set; }
            public string test_string { get; set; }

        }
        ///// Class 2 Based On Demo_Interface
        class Test_Class2 : Demo_Interface
        {
            public int test_int { get; set; }
            public string test_string { get; set; }

        }

        //// And Main Class
        class Main_Class
        {
            public List<Test_Class1> class_list_1 { get; set; }

            public List<Test_Class2> class_list_2 { get; set; }

            public Main_Class()
            {
                class_list_1 = new List<Test_Class1>() { };
                class_list_2 = new List<Test_Class2>() { };
            }
        }

        //// Console Main
        static void Main(string[] args)
        {
            var new_main_class = new Main_Class();

            Output_Class(new_main_class.class_list_1); ///// ==> ERROR

            Console.ReadKey();
        }

        //// Simple Function for do something with interface
        static void Output_Class(List<Demo_Interface> inter_input)
        {
            for (int i = 0; i < inter_input.Count; i++)
            {
                Console.WriteLine("{0} - {1}",i, inter_input[i].test_int);
            }
        }
    }
}

How Can I cast List<Test_Class1> to List<Demo_Interface> , When Test_Class1 uses Demo_Interface ? Test_Class1使用Demo_Interface时 ,如何将List<Test_Class1>List<Demo_Interface>

You can try 你可以试试

List<Test_Class1> testDemo = new List<Test_Class1>(); //list of Test_Class1 instances
List<Demo_Interface> result = testDemo.ToList<Demo_Interface>();

This is safe because we are not directly casting testDemo to its interface. 这是安全的,因为我们没有直接将testDemo强制转换为其接口。 We are keeping testDemo as it is and we are creating result which is list of Demo_Interface 我们保持testDemo,因为它是和我们正在创造result是列表Demo_Interface

If you need only to enumerate through the List<Demo_Interface> like shown in example, you don't have to do any kind of explicit casting. 如果仅需要像示例中所示通过List<Demo_Interface>进行枚举,则不必进行任何类型的显式转换。 List<T> implements IEnumerable<T> which is covariant generic type. List<T>实现IEnumerable<T> ,它是协变泛型类型。

Covariance for collections enables implicit conversion of a collection of a more derived type to a collection of a less derived type 集合的协方差允许将派生度更高的类型的集合隐式转换为派生度较小的类型的集合

In your case, List<Test_Class1> implements IEnumerable<Test_Class1> , but since Test_Class1 implements Demo_Interface , you can take advantage of generics variance and write, for example, something like this: 在您的情况下, List<Test_Class1>实现IEnumerable<Test_Class1> ,但是由于Test_Class1实现Demo_Interface ,您可以利用泛型方差并编写例如以下内容:

IEnumerable<Test_Class1> col = new List<Test_Class1>();
IEnumerable<Demo_Interface> colImplicit = col;

That basically means that your Output_Class method can take IEnumerable<Demo_Interface> argument and you'll be able to pass both lists without casting them explicitly using Cast<T> or creating a new collection using ToList<T> . 基本上,这意味着您的Output_Class方法可以使用IEnumerable<Demo_Interface>参数,并且您可以传递两个列表,而无需使用Cast<T>显式地转换它们或使用ToList<T>创建新的集合。

private void Output_Class(IEnumerable<Demo_Interface> inter_input)
{
    // do your thing
}

// Method invocation
Output_Class(new_main_class.class_list_1);

You cannot cast a List<ClassThatImplementsInterface> as a List<IInterfaceItImplements> . 您不能将List<ClassThatImplementsInterface>List<IInterfaceItImplements>

If you could, and you did this: 如果可以,并且您这样做:

var classList = new List<ClassThatImplementsInterface>();
var interfaceList = (List<IInterfaceItImplements>)classList;

... then you would be able to do this: ...那么您将能够执行此操作:

interfaceList.Add(new SomeOtherClassThatImplementsTheInterface);

But casting the list doesn't create a new list. 但是投射列表不会创建新列表。 In the above example there aren't two lists. 在上面的示例中,没有两个列表。 There are two variables with references to the same list. 有两个引用相同列表的变量。 If you could cast as seen above, you would be able to define a list of one type and add a completely different type to it. 如果可以如上所示进行转换,则可以定义一种类型的列表,并为其添加完全不同的类型。 The compiler prevents that. 编译器可以防止这种情况。

You could 你可以

  • create a new List<IDemoInterface> and add the items to it. 创建一个新的List<IDemoInterface>并将项目添加到其中。 (Or an array, IEnumerable, etc.) (或数组,IEnumerable等)
  • Leave the list as-is, and just cast individual items when/if you need to. 保留列表原样,并在需要时/仅投放单个项目。 In most cases we wouldn't need to cast something as an interface it implements. 在大多数情况下,我们不需要将某些内容转换为它实现的接口。

If we need to cast a whole collection as a different type, it's likely because we're passing it as an argument. 如果我们需要将整个集合强制转换为其他类型,则可能是因为我们将其作为参数传递。

That's actually a good reason not to define a method argument as a collection type like a List<T> which can be modified unless it's our intent to modify the collection. 实际上,这是一个很好的理由, 不要将方法参数定义为像List<T>这样的集合类型,可以修改它,除非我们打算修改集合。

That's one reason why we pass less-specific collection types, like IEnumerable<T> . 这就是为什么我们传递不太具体的集合类型(如IEnumerable<T>

Suppose the method argument looks like this: 假设方法参数看起来像这样:

void MethodINeedToPassTheArgumentTo(IEnumerable<IDemoInterface> items)

Now we can take our List<TestClass> and do this: 现在我们可以使用List<TestClass>并执行以下操作:

MethodINeedToPassTheArgumentTo(testClassList.Cast<IDemoInterface>);

We're not creating a new collection. 我们不会创建新集合。 We're passing a reference that allows the other method to view the items in the list, each individually cast as IDemoInterface . 我们正在传递一个引用,该引用允许其他方法查看列表中的项目,每个项目分别转换IDemoInterface For practical purposes it looks to the other method like a collection of IDemoInterface , and that's okay because the other item can't modify the collection. 出于实际目的,它看起来IDemoInterface的集合之类的另一种方法,这是可以的,因为另一项不能修改该集合。 It can't attempt to add other types into the List<TestClass> . 它不能尝试将其他类型添加到List<TestClass>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM