28

C #에서 제네릭에 관한 MSDN의 우수 기사를 읽었습니다.

내 머리 속에 떠오른 질문은 - 왜 제네릭 제약 조건을 사용해야합니까?

예를 들어, 다음과 같은 코드를 사용하면 :

public class MyClass<T> where T : ISomething
{
}

모든 참조를 전환 할 수 없습니다.T이 수업에서는ISomething?

이 방법을 사용하면 어떤 이점이 있습니까?


7 답변


47

당신은 묻습니다, "나는 모든T이 수업에서는ISomething"그래서 나는 당신이 다음과 같이 비교할 것을 의미한다고 생각합니다 :

public class MyClass<T> where T : ISomething 
{ 
    public T MyProperty { get; set; }
}

와:

public class MyClass 
{
    public ISomething MyProperty { get; set; }
}

두 번째 예에서,MyProperty의 인스턴스 일 뿐이다.ISomething. 첫 번째 예에서,MyProperty뭐든간에T그것이 특정 하위 유형 인 경우에도ISomething. 구체적인 구현을 고려하십시오.ISomething:

public class MySomething : ISomething
{
    public string MyOtherProperty { get; set; }
}

이제 첫 번째, 일반적인 예를 사용하면 다음을 얻을 수 있습니다.

MyClass<MySomething> myClass = new MyClass<MySomething>();
Console.WriteLine(myClass.MyProperty.MyOtherProperty);

반면에 두 번째 예제를 사용하면 액세스 할 수 없습니다.MyOtherProperty그게 유일한 것으로 알려져 있기 때문에ISomething:

MyClass myClass = new MyClass();
Console.WriteLine(myClass.MyProperty.MyOtherProperty); // Won't compile, no property "MyOtherProperty"

다른 유형의 제약 조건이 유용한 이유는 참조 할 수 있다는 것입니다.MyProperty(유형T)에 액세스하고ISomething. 즉,ISomething다음과 같이 선언되었습니다.

public interface ISomething 
{
    public string SomeProperty { get; set; }
}

그럼 네가 접근 할 수있어.MyProperty.SomeProperty. 당신이where T : ISomething그럼 당신은 접근 할 수 없을거야.SomeProperty이후T오직 유형으로 만 알려질 것입니다.object.


8

안전을 입력하십시오. 예를 들어, 컨테이너를 작성한다고 가정합니다. 컨테이너를 매개 변수화하여 나중에 캐스트를 수행 할 필요없이 컨테이너에 무언가를 전달하고 적절한 형식으로 검색 할 수 있습니다. 컨테이너에 저장하려는 유형의 제약 조건을 정의하는 것입니다.


4

차이점의 예는 다음과 같습니다.List<>

이미지 목록은 일반적이지는 않지만 단지 사용합니다.IListElement어디에서나 대신 일반을 사용했습니다. 이제 당신이 이런 물건을 가지고 있다고 상상해보십시오.

class Element : IListElement
{
   public string Something { get; set; }
}

지금 나는 할 수있다.list.Add(element);실제와는 차이가 없을 것입니다.List<Element>. 그러나 데이터를 검색 할 때 사용하는 목록을 사용하면 다른 이야기입니다.IListElement그러면 데이터를 다시 캐스팅해야만Something그것에서. 따라서 나는해야 할 것입니다 :

string s = ((Element)list[0]).Something;

제네릭을 사용하면 다음과 같이 할 수 있습니다.

string s = list[0].Something;

많은 어려움을 줄여 줍니 다. 그보다 조금 더 나아갑니다. 그러나 나는 당신이 이것으로부터 아이디어를 얻을 수 있다고 생각합니다.


2

첫 번째로, 코드 내의 ISomething에 정의 된 메소드를 제네릭 클래스의 일반 메소드 / 메소드에 대해 호출 할 수 있습니다. T가 어떤 타입이라도 허용된다면 (비록 당신은 항상 런타임 캐스팅을 할 수 있지만) 이것은 불가능합니다.

따라서 T가 될 수있는 것에 대한 컴파일 타임 제한을 적용 할 수 있으므로 코드 작성시 이러한 제약 조건에 의존하여 런타임 오류를 컴파일 타임 오류로 변환 할 수 있습니다.


1

네, T 대신에 뭔가를 사용할 수는 있지만 수동으로 할 것입니다.닫기제네릭 타입은 일반 클래스에 속한다. 더 이상 제네릭 형식이 아닙니다. T를 사용하면 형식을 유지할 수 있습니다.열다원하는만큼 많은 하위 유형을 사용할 수 있습니다.타입 안전을 손상시키지 않으면 서 코드 재사용이 핵심 이점입니다.예를 들어, ISomethings의 스택을 사용하는 경우 ISomething을 스택으로 푸시 할 수 있지만 ISomething의 실제 하위 유형에 대한 다운 캐스트와 함께 팝이 발생해야만 유용합니다. 다운 캐스팅은 일반적인 실패 지점을 만듭니다.Stack<T>어디 T : 뭔가


0

당신의 클래스의 소비자는 다른 것들 중에서 증가 된 타입 안전의 이점을 얻습니다.

class Widget : IPokable { }

// No generics
Widget w = (Widget)list[0]; // cast can fail

// With generics
Widget w = list[0];

제네릭이 없으면 목록에 포함 된 경우IPokable사물,캐스트가 여전히 필요하다..

구현중인 클래스는 일반 객체에 특정 메소드를 사용하는 이점을 얻습니다.

class PokableList<T> where T : IPokable {
    public T PokeAndGet() {
        currentObj.Poke();
        return currentObj;
    }
}


0

이 YouTube 비디오는 실제로 제네릭 제약의 중요성을 보여줍니다.https://www.youtube.com/watch?v=GlqBRIgMgho.

이제 아래에 긴 텍스트 답변이 나옵니다.

"Generic은 논리를 데이터 유형에서 분리하는 데 도움이됩니다. 그래서 우리는   높은 재사용 성을 위해 모든 로직을 첨부하십시오. "

그러나 여러 번 어떤 로직은 특정 데이터 유형에만 첨부 될 수 있습니다.

public class CompareNumeric<UNNKOWDATATYPE>
{
        public bool Compareme(UNNKOWDATATYPE v1, UNNKOWDATATYPE v2)
        {
            if (v1 > v2)
            {return true;}
            else
           {return false;}
        }
}

예를 들어 위의 예는 하나의 숫자가 다른 숫자보다 큰 경우 비교를 수행하는 간단한 제네릭 클래스입니다. 이제 더 크고 작은 비교는 숫자 데이터 유형에 매우 한정적입니다. 이러한 종류의 비교는 문자열과 같은 숫자가 아닌 유형에는 수행 할 수 없습니다.

그래서 어떤 사람들은 "int"타입의 클래스를 사용하면 완벽하게 유효합니다.

CompareNumeric<int> obj = new CompareNumeric<int>();
bool boolgreater = obj.Compare(10,20);

누군가가 "double"데이터 형식을 사용하면 다시 완벽하게 유효합니다.

CompareNumeric<double> obj = new CompareNumeric<double>();
bool boolgreater = obj.Compare(100.23,20.45);

그러나이 논리로 문자열 데이터 형식을 사용하면 바람직하지 않은 결과가 발생합니다. 그래서 우리는 제네릭 클래스에 어떤 타입의 타입이 첨부 될 수 있는지에 대한 제한을 두거나 제한하고자합니다. 이것은 "generic constraints"를 사용함으로써 성취됩니다.

CompareNumeric<string> obj = new CompareNumeric<string>();
bool boolgreater = obj.Compare(“interview”,”interviewer”);

다음 코드와 같이 일반 클래스 뒤에 "WHERE"키워드를 사용하여 데이터 유형을 지정하면 일반 유형을 제한 할 수 있습니다. 이제 클라이언트가 "문자열"데이터 유형을 아래 클래스와 연결하려고하면 허용되지 않으므로 바람직하지 않은 결과가 발생하지 않습니다.

public class CompareNumeric<UNNKOWDATATYPE> where UNNKOWDATATYPE : int, double
{

}


연결된 질문


관련된 질문

최근 질문