2011-04-19 3 views
6

Java에서는 Class가 generic 매개 변수 인 X를 사용하는 것이 편리합니다. 그러나 C#의 Type 클래스에는이 매개 변수가 없습니다. Java 클래스 <X> 유형의 C#에 해당하는 항목은 무엇입니까?

그래서 C#으로, 어떻게 하나 다음과 같은 자바 코드에 해당?

public <X> X methodThatReturns(Class<X> clazz) { ... } 

그 반환 값을 연결하는 C#에서 방법과 전달 된 유형이있을 것 같지 않습니다합니까.

대한 설명
여러 답변이 방법은 단순히 methodThatReturns<X>()로 정의 될 수 있기 때문에 메소드 매개 변수를 제안하는 것은 필요하지 않습니다 있습니다.

하지만이 알 수없는 유형의 변수가 할 경우, t,이 유형 t의 객체가 반환되도록 이러한 일반적인 메소드를 호출 할 수있는 방법은 기본적으로 없다?

Java에서는 형식 정보를 잃지 않고 Class<X> 개의 변수를 자유롭게 전달할 수 있지만 C#에서는 해당하는 Type 변수를 전달하면 사용할 수 없으므로 제한 사항에 부딪 힐 수 있습니다. 일반적인 메소드를 호출해야 할 때. C#에서 그래서 당신이 경우 클래스의 걱정없이 typeof(T) 같은 일을 할 수있는 유형의 삭제는 오히려 자바 "클래스"개체는 "일부 클래스"가 아닌 것으로 의미가 없다는 것을 염두에 또한

+0

http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx – asawyer

+2

저는 C# 프로그래머가 아니지만이 관용구는 훨씬 덜 일반적이라고 생각합니다. C#에서는 형식 지우기가 없기 때문에 C#에서. 일반 유형 정보는 런타임에 손실되지 않고 유지됩니다. –

+0

하나는 없다고 생각합니다. – clamchoda

답변

9
public X methodThatReturns<X>(Class<X> clazz) { ... } 

유지 자리 표시 자 :

public X methodThatReturns<X>(X value) 
{ 
    Type x = typeof(X); // that's fine 
    if (value is SomeType) { } // that's fine too  
    return (X)someObject; // I think you get the point 
} 

편집 : 일반 유형의 정보를 컴파일 후 손실되지 않기 때문에

다시 말하지만, 당신은 명시 적으로 타입을 전달 할 필요가 없습니다 :

C#에서 16,
public X methodThatReturns<X>() 
{ 
    Type xType = typeof(X); // Type is to C#/.Net what Class<X> is to Java. 
} 
+0

Ivan에게 감사 드려요. 그러나 X의 인스턴스가 아니라 매개 변수로 X의 "Type"을 가져 오는 방법을 찾고 있습니다 ... 과 같은 것입니다. – slattery

+0

매개 변수로 취할 방법이 없지만 C#에서는 매개 변수가 없더라도 메서드 내에서 수행 할 필요가 없습니다. 'Type x = typeof (X)'. Type은 C#의 Class와 같습니다. –

+0

이것은 매우 불행합니다. 전달 된 타입을 통해 동적 인 리턴 타입을 표현하고 컴파일러 타입 검사를하는 방법이 없으면 어떤 경우에는 매우 제한적이다. – andyczerwonka

3

public X methodThatReturns<X>() { ... } 

것 당신은 typeof(X)를 사용하는 대신 매개 변수 clazz

1

내가 자바 제네릭에 대한 100 %의 최대이야을 사용하여 X의 유형을 얻을 수 있습니다 ... 전달 된 것과 동일한 유형을 반환하는 메소드를 선언하려고합니까?

public T MethodThatReturns<T>(T input) { ... } 

이 방법은 모든 유형에 대해 일반적이며 통과 된 것과 동일한 유형을 반환합니다. 사용이 호출 할 수 있습니다 MethodThatReturns에 대한 호출에는 <AnyTypeAtAll>이 없습니다

AnyTypeAtAll foo = new AnyTypeAtAll(); 
AnyTypeAtAll bar = MethodThatReturns(foo); 

하는 것으로, 컴파일러는 전달 된 매개 변수를 주어진 그것을 알아낼 수 있습니다. 그러나 컴파일러는 런타임이 아닌 컴파일러이므로 foo가 가리키는 객체 유형이 아닌 변수 foo 유형 만 사용합니다.즉 단순히 어떤 '진짜'매개 변수를 사용하지 않는 방법에 대한 Java 구문을인지 한편


:

public T MethodThatReturns<T>() 
{ 
    Type clazz = typeof(T); 
    .... 
} 

이 방법 내에서, 당신은 T 당신이하는 것처럼 동일하게 처리 할 수 ​​있습니다 어떤 다른 클래스, 그리고 그것은 구체적으로 해당 메서드가 호출 된 형식을 참조 할 것입니다. object 또는 그와 비슷한 것이 아닙니다. 당신은 기본 생성자를 가지고 일반 유형을 제한 (일반 유형으로 int을 사용하지 못하도록 않습니다), 또는 where T : new() 그 방법 null로 비교를 할 수 있도록 where T : class을 넣어 할 수 있습니다, 그래서 당신은 할 수 T foo = new T();

0

Java 및 .NET 제네릭에 익숙하며 Java 프로젝트에서 많이 사용하는 Class<X> 구조를 사용합니다. 내가 가장 좋아하는 용도 중 하나는 Hibernate와 같은 외부 코드에서 반환되는 Java의 비 제네릭 컬렉션을 처리하는 것입니다. (나는 Hibernate의 최신 버전이 제네릭을 지원할 것이라고 생각하지만, 확실하지는 않습니다. 그 이후의 이전 버전은 우리가 이제까지을 변경 한 경우 업데이트해야 할 것이다 너무 많은 코드가 장기 실행 프로젝트) 기능은 다음과 같이 작동합니다.

public <X> List<X> TypedList(List<?> lst, Class<X> cls) { 
    return (List<X>) lst; 
} 

그것은 모두 매우 간단하고 중요한 일이 함수에 전달할 더미 객체를 만들 필요가 없으며 단지 다음과 같이 호출해야합니다.

List<MyObject> myLst = TypedList(lst, MyObject.class); 

주목해야 할 또 다른 중요한 사항은 다음과 같습니다. cls 매개 변수가 전혀 사용되지 않습니다. X에 대한 구체적인 유형을 제공하는 방법 일뿐입니다.

C#에서 이와 동일한 작업을 수행하는 방식이 조금 다릅니다. 당신은 동일한 기능은 다음과 같이 보일 것이라고 생각 :

public List<X> TypedList<X>(IList lst) 
{ 
    return (List<X>) lst; 
} 

하지만 당신은 죽은 잘못입니다.

문제는 자바가 기본적으로 코드가 실제로 컴파일 할 때, 모든 일반 매개 변수는 코드에서 제거되는 것을 의미 유형 소거라는 트릭을 사용한다는 것입니다. 따라서 Java 가상 머신의 세계에는 List<X> 또는 다른 제네릭과 같은 것이 없으며 모두 단순한 List 및 기타 일반 유형이 아닙니다. 즉, 제네릭은 코드 작성을 돕기위한 용도로만 사용되며 런타임에는 시행되지 않습니다.

그러나 C#에서는 런타임에 적용되는 형식 삭제가없고 입니다. 이것은 상기 함수와 함께 사용하면 다음과 같은 런타임 예외를 생성 할 것이라는 점을 의미

List<object> lstObj = TypedList<object>(new List<string>()); 

이유 List<string>List<object>과는 완전히 다른 두 종류로 간주된다는 것이다. 컴파일러 오류가 발생하지 않고 List<object> lstObj = (List<object>) new List<string>();도 수행 할 수 없습니다. 이것은 함수가 전달 된 동일한 객체를 반환 할 수 없음을 의미합니다. 우리는 이어야합니다. 올바른 유형의 새 개체를 만들고 그 개체를 반환해야합니다.가장 기본적인 형태는 다음과 같습니다.

public List<X> TypedList<X>(IList lst) 
{ 
    List<X> lstOut = new List<X>(); 
    for (int i = 0; i < lst.Count; i++) 
    { 
     if (lst[i] is X) lstOut.Add((X) lst[i]); 
    } 
    return lstOut; 
} 

오히려 지루하고 보일러 코드이지만 작동합니다. 훨씬 더 짧고 깨끗한 것을 위해 LINQ가 오늘을 구하기 위해 왔습니다. 다음 체크 아웃 :

public List<X> TypedList<X>(IList lst) 
{ 
    return lst.OfType<X>().ToList(); 
} 

OfType<X>()는 타입 X (또는 후손)의이다 LST에있는 모든 항목을 잡고 수없는 그 어떤 건너 뜁니다. ToList()OfType<X>()에서 전달 된 모든 구성원을 포함하는 List<X>을 새로 만듭니다. 이 방법의 또 다른 장점은 lst 매개 변수를 실제로 IList에서 IEnumberable으로 변경할 수 있으며 모든 컬렉션 유형에 의해 구현된다는 것입니다.

또 다른 한가지는 유형에 대한 변환을하지 않으며 형식 검사 만 수행한다는 것입니다. 따라서 List<long>을 사용하여 List<int> 또는 List<string>으로 변환하려면 다른 작업을 수행해야합니다. LINQ와 함께,이 여전히 매우 간단 할 것 :

List<long> lstLng = new List<long>(); 
lstLng.Add(1); 
List<int> lstInt = lstLng.Cast<int>().ToList(); 
List<string> lstStr = lstLng.Select(lng => lng.ToString()).ToList(); 

[참고 :. 당신이 lng => lng.ToString() 부분에 익숙하지 않은 경우가 람다 식라고]

Cast<int>() 달리 OfType<int>(), 실제로 각 항목을 int로 변환하고 변환하지 못하는 항목은 건너 뜁니다. Select()을 사용하면 원하는 거의 모든 종류의 코드를 사용하여 기존 컬렉션에서 완전히 새로운 컬렉션을 만들 수 있습니다.

실제 예제를 사용하면 일반 유형의 함수를 사용할 때 .NET과 Java의 차이점을 더 잘 이해할 수 있기를 바랍니다.

+0

흥미로운 읽기. 현재 상황에서 도움이되는 LINQ 메소드를 찾았 기 때문에 다행입니다. 하지만 특별한 숨겨진 것이 있다고 생각하지 않습니다. 이미 내장 된 하나가 있다는 것을 깨닫기 전에 실제로 OfType 확장 메서드를 만들었습니다. 리스트 에서리스트 으로가는 한계는 아마도 유형 차이와 관련이 있습니다. 나는 여전히 C# 3.5를 사용하고 있지만, 4.0에서는 공분산과 반항에 대한 'in'과 'out'키워드와 같은 더 많은 지원을 도입했다고 생각합니다. – slattery

+0

@slattery 실제로 분산은 클래스, 인터페이스 및 델리게이트에만 적용되지 않습니다.List는 공 변성 인 IEnumerable을 구현하기 때문에'IEnumerable enumObj = new List (); '과 같은 작업을 할 수는 있지만 여전히 ListlstObj = (List ) enumObj; 콘크리트 유형이 항상 List 이 될 것이므로 예외를 캐스팅하십시오. 따라서, List lstObj = lstStr.OfType () .ToList();와 같은 일을하면 완전히 새로운 List 객체가 생성되고 할당됩니다. – CptRobby

+0

@slattery 분산에 대한 자세한 내용은이 기사를 참조하십시오. http://msdn.microsoft.com/en-us/library/dd799517.aspx. IEnumberable 은 변형이며 ICollection 은 그렇지 않습니다. 그 이유는 ICollection 에 정의 된 일부 메소드가 T를 매개 변수로 사용하기 때문입니다. (Contravariance 여전히 내 마음을 망칠 ... LOL) 귀하의 의견을 주셔서 감사합니다. ;-) – CptRobby

관련 문제