C #-하나의 목록에 여러 제네릭 형식


153

이것은 아마도 불가능하지만이 수업이 있습니다.

public class Metadata<DataType> where DataType : struct
{
    private DataType mDataType;
}

더 많은 것이 있지만 간단하게 유지합시다. 일반 유형 (DataType)은 where 문에 의해 값 유형으로 제한됩니다. 내가하고 싶은 것은 다양한 유형 (DataType)의 메타 데이터 개체 목록입니다. 같은 :

List<Metadata> metadataObjects;
metadataObjects.Add(new Metadata<int>());
metadataObjects.Add(new Metadata<bool>());
metadataObjects.Add(new Metadata<double>());

이것도 가능합니까?


24
아래의 답변에서 접근 방식에 실제 이점이 있는지 궁금합니다 List<object>. 그들은 권투 / 언 박싱을 멈추지 않으며, 캐스팅의 필요성을 제거하지 않을 것이며, 궁극적으로 Metadata실제에 대해 아무것도 알려주지 않는 객체를 얻습니다 DataType. 나는 그 문제를 해결할 솔루션을 찾고있었습니다. 인터페이스 / 클래스를 선언하려는 경우 구현 / 파생 일반 유형을 일반 목록에 넣을 수 있기 때문에 의미없는 레이어가 아닌 다른 것을 사용 하는 것과 다른 점List<object>무엇입니까?
Saeb Amini

9
추상 기본 클래스와 인터페이스는 모두 목록에 추가 할 수있는 요소 유형을 제한하여 제어 수준을 제공합니다. 또한 권투가 어떻게 나오는지 알 수 없습니다.
0b101010

3
물론 .NET v4.0 이상을 사용하는 경우 공분산이 솔루션입니다. List<Metadata<object>>트릭을 수행합니다.
0b101010

2
@ 0b101010 나는 똑같은 생각을했지만 불행히도 값 유형에는 차이가 허용되지 않습니다. OP에는 struct제약 조건 이 있으므로 여기서 작동하지 않습니다. 참조
nawfal

@ 0b101010, 둘 다 참조 유형 만 제한하고 내장 된 값 유형 및 모든 구조를 계속 추가 할 수 있습니다. 또한 결국 MetaData에는 각 요소의 기본 값 유형에 대한 정보 (컴파일 시간)가없는 원래 값 유형 대신 참조 유형 목록이 있습니다. 이는 실제로 "박싱"입니다.
Saeb Amini

답변:


195
public abstract class Metadata
{
}

// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
    private DataType mDataType;
}

5
와! 나는 그것이 가능하다고 생각하지 않았다! 당신은 생명의 은인입니다!
Carl

2
이것을 위해 +10! 이것이 왜 컴파일되는지 모르겠습니다. 정확히 내가 필요한 것!
Odys December

비슷한 문제가 있지만 제네릭 클래스가 다른 제네릭 클래스에서 확장되므로 솔루션을 사용할 수 없습니다 ...이 상황에 대한 해결책에 대한 아이디어가 있습니까?
Sheridan

10
간단한 방법과 비교하여이 방법에 이점이 List<object>있습니까? OP의 질문에 게시 된 내 의견을보십시오.
Saeb Amini

11
@SaebAmini List <object>는 개발자에게 의도를 보여주지 않으며, 일부 메타 데이터 이외의 개체를 목록에 잘못 추가하여 개발자가 발에 쏠 수 없도록합니다. List <MetaData>를 사용하여 목록에 포함되어야하는 내용을 이해합니다. 대부분의 MetaData에는 위의 예제에서 보여지지 않은 공개 속성 / 방법이있을 것입니다. 객체를 통해 액세스하려면 번거로운 캐스팅이 필요합니다.
Buzz

92

leppie의 답변에 따라 MetaData인터페이스를 만드십시오 .

public interface IMetaData { }

public class Metadata<DataType> : IMetaData where DataType : struct
{
    private DataType mDataType;
}

누군가이 접근법이 더 나은 이유를 말해 줄 수 있습니까?
Lazlo

34
공통 기능이 공유되지 않기 때문에 왜 기본 클래스를 낭비합니까? 인터페이스가 충분합니다
flq

2
struct에서 인터페이스를 구현할 수 있기 때문입니다.
Damian Leszczyński-Vash는

2
그러나 가상 메소드를 사용한 클래스 상속은 인터페이스 메소드보다 약 1.4 배 빠릅니다. 따라서 MetaData <DataType>에서 제네릭이 아닌 MetaData (가상) 메소드 / 속성을 구현하려는 경우 성능이 문제가되는 경우 인터페이스 대신 추상 클래스를 선택하십시오. 그렇지 않으면 인터페이스를 사용하는 것이 더 유연 할 수 있습니다.
TamusJRoyce

30

또한 new키워드를 사용하여 제네릭이 아닌 버전을 사용했습니다 .

public interface IMetadata
{
    Type DataType { get; }

    object Data { get; }
}

public interface IMetadata<TData> : IMetadata
{
    new TData Data { get; }
}

명시 적 인터페이스 구현은 두 Data멤버 모두를 허용하는 데 사용됩니다 .

public class Metadata<TData> : IMetadata<TData>
{
    public Metadata(TData data)
    {
       Data = data;
    }

    public Type DataType
    {
        get { return typeof(TData); }
    }

    object IMetadata.Data
    {
        get { return Data; }
    }

    public TData Data { get; private set; }
}

버전 타겟팅 값 유형을 도출 할 수 있습니다.

public interface IValueTypeMetadata : IMetadata
{

}

public interface IValueTypeMetadata<TData> : IMetadata<TData>, IValueTypeMetadata where TData : struct
{

}

public class ValueTypeMetadata<TData> : Metadata<TData>, IValueTypeMetadata<TData> where TData : struct
{
    public ValueTypeMetadata(TData data) : base(data)
    {}
}

이것은 모든 종류의 일반적인 제약으로 확장 될 수 있습니다.


4
사용 방법을 보여 주었기 때문에 +1 ( DataType그리고 object Data많은 도움이 됨)
Odys

4
예를 들어 글을 쓸 수없는 것 같습니다 Deserialize<metadata.DataType>(metadata.Data);. 그것은 나를 말한다 기호 메타 데이터를 확인할 수 없습니다 . 일반 메소드에 사용하기 위해 DataType을 검색하는 방법은 무엇입니까?
Cœur
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.