문제

기본 클래스가 있습니다.

public abstract class StuffBase
{
    public abstract void DoSomething();
}

그리고 두 개의 파생 수업

public class Stuff1 : StuffBase
{
    public void DoSomething()
    {
        Console.WriteLine("Stuff 1 did something cool!");
    }
    public Stuff1()
    {
        Console.WriteLine("New stuff 1 reporting for duty!");
    }
}

public class Stuff2 : StuffBase
{
    public void DoSomething()
    {
        Console.WriteLine("Stuff 2 did something cool!");
    }
    public Stuff1()
    {
        Console.WriteLine("New stuff 2 reporting for duty!");
    }
}

좋아, 이제 항목 목록이 있다고 말합니다.

var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());

그리고 나는 그들 모두가 그들의 dosomething () 방법을 호출하기를 원합니다. 목록을 반복하고 그들의 dosomething () 메소드를 호출 할 것으로 기대할 수 있으므로 목록 위에 반복하고 작업을 수행하는 alldosomething ()이라는 방법이 있다고 가정 해 봅시다.

public static void AllDoSomething(List<StuffBase> items)
{
    items.ForEach(i => i.DoSomething());
}

다음 방법의 실제 차이점은 무엇입니까?

public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
    items.ForEach(i => i.DoSomething());
}

두 방법 모두 실제 용어로는 구문 적으로 다르지만 같은 일을하는 것으로 나타납니다.

그들은 똑같은 일을하는 다른 방법입니까? 제네릭과 유형 제약 조건을 이해하지만이 인스턴스에서 다른 방법을 사용하는 이유를 알 수 없습니다.

도움이 되었습니까?

해결책

아직 C#이 지원하지 않기 때문입니다. 공분산.

보다 공식적으로, c# v2.0에서 t가 u의 하위 유형 인 경우, t []는 u []의 하위 유형이지만 g는 g의 하위 유형이 아니다 (여기서 G는 일반 유형). 유형 이론 용어에서, 우리는 C# 배열 유형이 "공분산"이고 일반적인 유형이 "불변"이라고 말 함으로써이 동작을 설명합니다.

참조: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx

다음 방법이있는 경우 :

public static void AllDoSomething(List<StuffBase> items)
{
    items.ForEach(i => i.DoSomething());
}

var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile

일반 유형 제약 조건을 사용하는 경우.

공분산 및 비밀화에 대한 자세한 내용을 보려면] 확인하십시오. Eric Lippert의 일련의 게시물.


읽을 가치가있는 기타 게시물 :

다른 팁

목록이 있다고 가정합니다.

List<Stuff1> l = // get from somewhere

이제 시도하십시오 :

AllDoSomething(l);

일반 버전에서는 허용됩니다. 비 게 니체로는 그렇지 않습니다. 그것이 필수적인 차이입니다. 목록 Stuff1 목록이 아닙니다 StuffBase. 그러나 일반적인 경우, 당신은 정확히 목록이 될 필요가 없습니다. StuffBase, 더 유연합니다.

먼저 목록을 복사하여 그 일을 할 수 있습니다. Stuff1 목록으로 StuffBase, 비 게 릭 버전과 호환되도록합니다. 그러나 방법이 있다고 가정합니다.

List<T> TransformList<T>(List<T> input) where T : StuffBase
{
    List<T> output = new List<T>();

    foreach (T item in input)
    {
        // examine item and decide whether to discard it,
        // make new items, whatever
    }

    return output;
}

제네릭이 없으면 목록을 수락 할 수 있습니다 StuffBase, 그러나 당신은 다음과 같은 목록을 반환해야합니다. StuffBase. 발신자는 항목이 실제로 파생 된 유형이라는 것을 알고 있다면 캐스트를 사용해야합니다. 따라서 제네릭을 사용하면 실제 유형의 인수 유형을 보존하고 메소드를 통해 리턴 유형으로 채널 할 수 있습니다.

제공된 예에서는 차이가 없지만 다음을 시도하십시오.

List<Stuff1> items = new List<Stuff1>();
items.Add(new Stuff1());
AllDoSomething(items);
AllDoSomething<StuffBase>(items);

첫 번째 호출은 잘 작동하지만 두 번째 호출은 일반적인 공분산으로 인해 컴파일되지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top