C #에서 제네릭에 관한 MSDN의 우수 기사를 읽었습니다.
내 머리 속에 떠오른 질문은 - 왜 제네릭 제약 조건을 사용해야합니까?
예를 들어, 다음과 같은 코드를 사용하면 :
public class MyClass<T> where T : ISomething
{
}
모든 참조를 전환 할 수 없습니다.T
이 수업에서는ISomething
?
이 방법을 사용하면 어떤 이점이 있습니까?
당신은 묻습니다, "나는 모든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
.
안전을 입력하십시오. 예를 들어, 컨테이너를 작성한다고 가정합니다. 컨테이너를 매개 변수화하여 나중에 캐스트를 수행 할 필요없이 컨테이너에 무언가를 전달하고 적절한 형식으로 검색 할 수 있습니다. 컨테이너에 저장하려는 유형의 제약 조건을 정의하는 것입니다.
차이점의 예는 다음과 같습니다.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;
많은 어려움을 줄여 줍니 다. 그보다 조금 더 나아갑니다. 그러나 나는 당신이 이것으로부터 아이디어를 얻을 수 있다고 생각합니다.
첫 번째로, 코드 내의 ISomething에 정의 된 메소드를 제네릭 클래스의 일반 메소드 / 메소드에 대해 호출 할 수 있습니다. T가 어떤 타입이라도 허용된다면 (비록 당신은 항상 런타임 캐스팅을 할 수 있지만) 이것은 불가능합니다.
따라서 T가 될 수있는 것에 대한 컴파일 타임 제한을 적용 할 수 있으므로 코드 작성시 이러한 제약 조건에 의존하여 런타임 오류를 컴파일 타임 오류로 변환 할 수 있습니다.
네, T 대신에 뭔가를 사용할 수는 있지만 수동으로 할 것입니다.닫기제네릭 타입은 일반 클래스에 속한다. 더 이상 제네릭 형식이 아닙니다. T를 사용하면 형식을 유지할 수 있습니다.열다원하는만큼 많은 하위 유형을 사용할 수 있습니다.타입 안전을 손상시키지 않으면 서 코드 재사용이 핵심 이점입니다.예를 들어, ISomethings의 스택을 사용하는 경우 ISomething을 스택으로 푸시 할 수 있지만 ISomething의 실제 하위 유형에 대한 다운 캐스트와 함께 팝이 발생해야만 유용합니다. 다운 캐스팅은 일반적인 실패 지점을 만듭니다.Stack<T>
어디 T : 뭔가
당신의 클래스의 소비자는 다른 것들 중에서 증가 된 타입 안전의 이점을 얻습니다.
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;
}
}
이 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
{
}
int
또는double
제네릭 형식 매개 변수로. 마지막 예에서 사용한 이것 좀 봐stackoverflow.com/questions/11770882/… - Bharat