C #에 new () 제약 조건이 있지만 다른 유사한 제약 조건이없는 이유는 무엇입니까?


19

C # 제네릭에서는 형식 매개 변수 T가 기본 생성자를 갖도록 제약 조건을 선언 할 수 있습니다 where T : new(). 그러나 이와 같은 다른 제약 조건은 유효하지 않습니다 ( new(string)예 : 등).

언어 설계 및 / 또는 구현 관점에서 그 이유는 무엇입니까?

생성자가 작동하는 방식이나 유형 시스템이 구현되는 방식으로 이것을 금지하거나 최소한 어렵게 만드는 것이 있습니까? 그렇다면 무엇입니까? default(T)실제로 컴파일되는 어딘가를 읽은 것을 기억 new T()합니다 T : struct. 이것과 관련이 있습니까?

아니면 언어를 너무 복잡하게 만들지 않기 위해 단순히 디자인 결정을 내렸습니까?


new(string)기본 생성자 제약 조건이 아닙니다. "특정 생성자 서명이 필요한 제약 조건이없는 이유는 무엇입니까?" 그러한 제약은 특별히 유용하지 않기 때문에 가능성이 높습니다.
Robert Harvey

3
@RobertHarvey 예, 정확히 제가 말하는 것입니다. 기본 생성자를 특별한 구현 방식으로 만들거나 다른 것을 포함하지 않는 임의의 선택인지 본질적으로 묻습니다.
Theodoros Chatzigiannakis

기본 생성자는 특정적이고 중요한 방식으로 유용합니다. 예를 들어, 형식을 쉽게 직렬화 할 수 있습니다.
Robert Harvey

6
특정 ctor 서명이 유용 할 수 있습니다. 예를 들어, 유형 변수가 ctor가 T (Collection <T>) 인 Collection <T>로 제한되는 경우 다른 지정된 새 콜렉션을 구성 할 수 있습니다. 그러나 그 유용성이 추가적인 복잡성의 가치가 있는지 여부는 의문입니다.
Phoshi

답변:


5

권위있는 답변을 위해 몇 년 전에 StackOverflow에 대한 질문에 대한 Eric Lippert의 답변 을 참조하십시오 . 스 니펫은 아래에 간략하게 인용되어 있습니다.

그러나이 특정 경우에 나는 디자인 회의에서 향후 버전의 언어에 대한 가능한 기능으로 기능이 제공되는 경우 해당 기능을 다시 사용해야하는 이유를 확실히 제시 할 수 있습니다.

...

우리는 전체 기능을 수행하거나 전혀 수행하지 않아야한다고 말합니다. 특정 생성자를 갖도록 유형을 제한하는 것이 중요하다면 생성자뿐만 아니라 일반적인 구성원을 기준으로 전체 기능을 수행하고 유형을 제한합시다.


2
문맥에서 벗어난 인용문은 매우 오해의 소지가 있습니다. 에릭은 마이크로 소프트가 자신의 입장이 아닌 "완전히 사라져야한다"고 생각했다. 그는 실제로 제안 된 기능과 정반대입니다.
Robert Harvey

1
고맙습니다, 이것은 내 질문에 부분적으로 대답합니다. 그의 대답이 끝날 무렵 Eric Lippert는 이것이 IL의 한계 이며이 기능을 포함하면 IL에 추가해야한다고 언급합니다. 당신이 IL이 부분에 대해 생성되는 사항에 대한 소스 제공 할 수 있다면 그것은 완벽 할 것 입니다 일반적으로 기본 생성자를 호출입니다 - 구현을.
Theodoros Chatzigiannakis

@ TheodorosChatzigiannakis : Telerik의 디 컴파일러를 시작하고 스스로 알아 내지 않겠습니까?
Robert Harvey

2
@RobertHarvey 나는 그것이 그를위한 입장을 전혀 제안하지 않는다고 생각하지만, 나는 그의 입장을 강조하기 위해 추가 인용문을 포함시켰다.
Chris Hannon

1
흠, F #에는 클래스에 연산자가 있는지 컴파일 시간으로 확인하는 것과 같이 유형을 제한하는 고급 방법이 있습니다. 아마도 F #은 매우 엄격한 유형 검사로 인해 C #보다 강력한 제약 시스템이 필요합니다. 그럼에도 불구하고이 언어는 .Net Framework에서 클래스를 구성하는 고급 방법을 구현할 수 있습니다.
OnesimusUnbound

16

로버트 하비의 제안에 따라 디 컴파일은 다음과 같은 관심을 가진 사람들에게 다음과 같은 결과를 주었다. 이 방법:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

분명히 컴파일되면 다음과 같이됩니다.

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • 경우 T값 형식이고, new()이된다 default(T).
  • T참조 유형 인 경우 new()리플렉션을 사용하여 작동합니다. Activator.CreateInstance()내부적으로 호출합니다 RuntimeType.CreateInstanceDefaultCtor().

내부적으로 기본 생성자는 CLR과 관련하여 실제로 C #에 특별합니다. 다른 생성자에게 동일한 처리 방법을 제공하면 제네릭의 더 복잡한 제약 조건에 대한 유효한 사용 사례가 있더라도 비용이 많이들 것입니다.


4
흥미 롭군 default(T) 값 유형 을 중복 호출하는 이유는 무엇 입니까?
Avner Shahar-Kashtan

2
@ AvnerShahar-Kashtan 몰라요. t변수 와 같은 컴파일 / 디 컴파일 프로세스의 아티팩트 일 수 있습니다 (네스트 된 return명령문 으로 대체 될 수 있음 ).
Theodoros Chatzigiannakis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.