C # Generics에서 "기본"형식 매개 변수에 대한 합리적인 접근 방식이 있습니까?


93

C ++ 템플릿에서 특정 유형 매개 변수가 기본값임을 지정할 수 있습니다. 즉, 명시 적으로 지정하지 않는 한 유형 T를 사용합니다.

C #에서이 작업을 수행하거나 근사화 할 수 있습니까?

다음과 같은 것을 찾고 있습니다.

public class MyTemplate<T1, T2=string> {}

따라서 명시 적으로 지정하지 않는 유형의 인스턴스는 다음과 T2같습니다.

MyTemplate<int> t = new MyTemplate<int>();

본질적으로 다음과 같습니다.

MyTemplate<int, string> t = new MyTemplate<int, string>();

궁극적으로 상당히 널리 사용되는 템플릿이있는 경우를보고 있지만 추가 유형 매개 변수로 확장을 고려하고 있습니다. 나는 하위 클래스를 가질 수 있지만,이 맥락에서 다른 옵션이 있는지 궁금했습니다.

답변:


77

서브 클래 싱이 최선의 선택입니다.

주요 일반 클래스를 하위 클래스로 지정합니다.

class BaseGeneric<T,U>

특정 클래스와 함께

class MyGeneric<T> : BaseGeneric<T, string>

이렇게하면 논리를 한 위치 (기본 클래스)에 쉽게 보관할 수 있지만 두 가지 사용 옵션을 모두 쉽게 제공 할 수 있습니다. 수업에 따라이를 수행하는 데 필요한 추가 작업이 거의 없을 것입니다.


1
아 ... 말이 되네요. 유형 매개 변수가 고유 한 서명을 제공하는 경우 유형 이름이 동일 할 수 있습니까?
el2iot2

2
@ee : 예, 제네릭은 overloadable매개 변수 수를 기준으로합니다.
Mehrdad Afshari

@ee : 예,하지만 그렇게하는 것을 조심할 것입니다. 그렇게하는 것은 .NET에서 "합법적"이지만 혼동을 유발할 수 있습니다. 차라리 문자열 파생 유형의 이름이 기본 제네릭 클래스와 비슷하지만 (찾기 쉬운 것이 무엇인지 명확하게 알 수 있음) 문자열임을 분명히하는 이름을 사용합니다.
Reed Copsey

@Reed : 정말 혼란 스럽습니까? 이 특별한 경우에는 같은 이름을 사용하는 것도 도움이된다고 생각합니다. .NET에는 동일한 작업을 수행하는 예제가 있습니다. 예를 들어 Func <> 대리자입니다.
Mehrdad Afshari

4
예를 들어 Predicate <T>는 Func <T, bool> 일 뿐이지 만 용도가 다르기 때문에 이름이 변경되었습니다.
Reed Copsey

19

한 가지 해결책은 서브 클래 싱입니다. 대신 사용할 또 다른 방법은 팩토리 메서드 (var 키워드와 결합)입니다.

public class MyTemplate<T1,T2>
{
     public MyTemplate(..args..) { ... } // constructor
}

public static class MyTemplate{

     public static MyTemplate<T1,T2> Create<T1,T2>(..args..)
     {
         return new MyTemplate<T1, T2>(... params ...);
     }

     public static MyTemplate<T1, string> Create<T1>(...args...)
     {
         return new MyTemplate<T1, string>(... params ...);
     }
}

var val1 = MyTemplate.Create<int,decimal>();
var val2 = MyTemplate.Create<int>();

위의 예에서 val2형인 MyTemplate<int,string> 아니라 이로부터 파생 된 타입.

유형 class MyStringTemplate<T>:MyTemplate<T,string>이와 같은 유형 이 아닙니다 MyTemplate<T,string>. 이로 인해 특정 시나리오에서 몇 가지 문제가 발생할 수 있습니다. 예를 들어의 인스턴스 MyTemplate<T,string>MyStringTemplate<T>.


3
이것이 가장 유용한 접근 방식입니다. 아주 좋은 해결책
T-moty 2015-06-04

12

다음과 같이 클래스 오버로드를 만들 수도 있습니다.

public class MyTemplate<T1, T2> {
    public T1 Prop1 { get; set; }
    public T2 Prop2 { get; set; }
}

public class MyTemplate<T1> : MyTemplate<T1, string>{}

귀하의 솔루션이 다른 솔루션과 동일하기 때문에 늦은 답변을 게시하기 전에 다른 답변을 읽으십시오.
Cheng Chen

7
허용 대답은 내 솔루션은 동일한 클래스 과부하되고, 다른 이름으로 클래스를 생성 한
Nerdroid

2
아니요, 둘 다 새 수업을 만들고 있습니다. 여기서 이름은 중요하지 않습니다. MyTemplate<T1>에서 다른 클래스 MyTemplate<T1, T2>도, AnotherTemplate<T1>.
Cheng Chen

7
명확하고 정확한 실제 유형이 다르더라도 같은 이름을 유지하면 코딩이 더 쉽습니다. 클래스 "오버로드"가 그런 방식으로 사용될 수 있다는 것은 모든 사람에게 분명하지 않습니다. @DannyChen이 옳습니다-기술적 관점에서 보면 결과는 동일하지만 OP가 요청한 것을 달성하는 데 더 가깝습니다.
Kuba

1
MyTemplate<T1, string>MyTemplate<T1>
안타깝게도이

10

C #은 이러한 기능을 지원하지 않습니다.

말했듯이 (봉인되지 않은 경우 모든 생성자 선언을 복제하는 경우) 하위 클래스를 만들 수 있지만 완전히 다른 것입니다.


3

불행히도 C #은 사용자가하려는 작업을 지원하지 않습니다. 매개 변수의 기본 형식이 제네릭 제약 조건을 준수해야하고 CLR이 형식 안전성을 보장하려고 할 때 골칫거리가 될 가능성이 높기 때문에 구현하기 어려운 기능입니다.


1
별로. 속성 (VB.NET의 기본 매개 변수와 같은)을 사용하여 수행 할 수 있으며 컴파일러가 컴파일시이를 대체하도록 할 수 있습니다. 주된 이유는 C # 디자인 목표입니다.
Mehrdad Afshari

컴파일러는 기본 매개 변수가 일반 제약 조건을 충족하는지 확인해야합니다. 또한 메서드의 형식 매개 변수에 대해 가정하면 기본이 아닌 형식 매개 변수가 상속되어야하기 때문에 기본 매개 변수는 일반 제약 조건 자체가됩니다.
Andrew Hare

@Andrew, 기본 매개 변수는 일반 제약 조건 일 필요는 없습니다. 이것이 C ++의 기본 템플릿 매개 변수처럼 동작한다면 automatonic의 클래스를 확장하는 것은 완벽하게 괜찮을 것입니다. MyTemplate <int, float> x = null T2에는 제네릭 제약이 없기 때문에 기본 문자열 유형에도 불구하고 float는 괜찮습니다. . 이런 식으로 기본 템플릿 매개 변수는 기본적으로 MyTemplate <int>를 MyTemplate <int, string>의 약어로 작성하기위한 "구문 적 설탕"일뿐입니다.
Tyler Laing

@Andrew, 저는 C # 컴파일러가 이러한 기본 템플릿 매개 변수가 기존의 일반 상수를 충족하는지 확인해야한다는 데 동의합니다. C # 컴파일러는 이미 클래스 선언에서 비슷한 것을 확인합니다. 예를 들어 "where U : ISomeInterface"와 같은 일반 제약 조건을 Reed의 BaseGeneric <T, U> 클래스에 추가하면 MyGeneric <T>가 오류와 함께 컴파일에 실패합니다. 기본 템플릿 매개 변수를 확인하는 것은 매우 동일합니다. 컴파일러는 클래스 선언을 확인하고 오류 메시지는 동일하거나 매우 유사 할 수 있습니다.
Tyler Laing

"구현하기 어려운 기능이 될 것입니다."그건 말도 안됩니다. 구현하는 것은 사소한 일입니다. 후보 유형이 파일의 다른 위치 (즉, 템플릿 인스턴스화가 아닌 템플릿에서)에 나타나기 때문에 템플릿 제약 조건에 대해 유형의 유효성을 검사하는 작업이 더 어려워지지 않습니다.
Mud
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.