2009-03-18 12 views
3

(. 감사합니다 답변에 대한 모든 사람, here is my refactored example은 다시 단일 책임 원칙에 대한 또 다른 StackOverflow의 질문)메서드 시그니처에 제네릭을 사용하면 어떤 이점이 있습니까?

C 번호로 PHP에서오고,이 구문은 협박했다 :

container.RegisterType<Customer>("customer1"); 

나는 실현 될 때까지 다음 코드와 같은 내용을 표현한 것과 같습니다.

container.RegisterType(typeof(Customer), "customer1"); 

그래서 제네릭이 (예를 들어, 유니티 대부분의 C# IOC의 컨테이너를 통해) 여기에 사용되는 이유 몇 가지 이유 당신이 대해서 typeof 필요하지 않습니다 즉, 그냥 청소기 구문 것보다 다른이()는 유형을 보낼 때?

using System; 

namespace TestGenericParameter 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Container container = new Container(); 
      container.RegisterType<Customer>("test"); 
      container.RegisterType(typeof(Customer), "test"); 

      Console.ReadLine(); 
     } 
    } 

    public class Container 
    { 
     public void RegisterType<T>(string dummy) 
     { 
      Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name); 
     } 

     public void RegisterType(Type T, string dummy) 
     { 
      Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name); 
     } 

    } 

    public class Customer {} 
} 

//OUTPUT: 
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer 
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer 

답변

5

가장 큰 이유는 컴파일 타임에 유형 안전성 때문입니다. 두 개의 Type 개체를 전달하는 경우 컴파일러 대신 개발자에게 책임이 있습니다.

따라서 콘크리트 유형이 추상 유형을 상속받지 않는 경우 컴파일러에서 불평 할 수 있으므로 많은 IoC 컨테이너에서이를 사용합니다. TConcrete가 구현하거나 TAbstract을 상속하는 경우

public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract 
{ 
} 

이 코드는 작동합니다. 이 메서드가 두 개의 Type 매개 변수를 사용하면 메서드에서이 관계를 확인해야합니다.

3

한 예를 들어, 일반적인 대 typeof 옵션을 사용하여 형식의 인스턴스를 만드는 데 필요한 코드를 비교합니다. 또는 형식의 인스턴스를 반환합니다. 또는 형식의 인스턴스를 인수로 사용합니다. 또는 유형의 인스턴스에 속성을 설정합니다.

일반적으로 유형 자체로만 작업하는 경우 유형 매개 변수를 사용할 수 있습니다. 유형이 인 인스턴스을 사용하여 작업을 수행하려는 경우 제네릭을 사용하십시오.

제네릭을 사용하는 또 다른 이유는 유형에 제약 조건을 적용하려는 경우입니다. 예를 들어, 유형이 하나 이상의 인터페이스를 구현하거나, 다른 유형을 상속하거나, 참조 유형 또는 값 유형이거나, 기본 생성자가 있거나, 또는 이들의 조합을 요구할 수 있습니다. 컴파일러는이를 적용하여 요구 사항을 준수하지 않는 코드를 작성할 수 없습니다.

3

기본 용도 중 하나는 인수 및 반환 값이있는 유형 안전성입니다. 입력/출력 유형 (문자열)이 일반 사례 (고객)와 일치하지 않기 때문에 귀하의 예제에서는 제네릭을 많이 사용하지 않습니다.

더 적절한 사용은 할 수 있습니다

public T RegisterType<T>(string name) 
{ 
    T obj = new T(); 
    obj.DoSomething(); 
    return obj; 
} 

아니면

public void DoSomething<T>(T obj) 
{ 
    //operate on obj 
} 
+0

매우 유용한 것처럼 들리지만이를 구현하려고하면 "T obj = new T();" 나에게 "new() 제약 조건이 없기 때문에 변수 유형 'T'의 인스턴스를 만들 수 없습니다." 내가 뭘 놓치고 있니? –

+1

내 대답과 같이 제약 조건을 추가해야합니다 :'public T CreateNew () T : new()' –

4

이유 중 하나는 제네릭이 매우 유용 할 때 제네릭 형식 매개 변수가 매개 변수 또는 유형으로 사용하면됩니다 반환 값의 형태 반환 형식은 컴파일러와 권투 값 유형을 확인할 수 있습니다

public T GetAs<T>(string name) 

같은 즉, 당신이 쓸 수있는 방법은 때로는 피할 수 있습니다.

int value = GetAs<int>("foo"); 

Whithout 제네릭, 당신은

public object GetAs(Type t, string name) 

를 작성해야하고 발신자는 다시 결과를 캐스팅해야한다 : 호출자 작성합니다

int value = (int)GetAs(typeof(int), "foo"); 
2

, 당신은하지 않았다 경우 Generics를 사용하려면 지원하려는 각 유형에 대해 메소드를 오버로드해야합니다. 그렇지 않으면 매개 변수를 객체로 받아 들여 캐스팅 로직을 수행해야합니다.

4

간단히 대답은 유형 추론 가능한 경우입니다. 일반 유형이 메소드 서명에 사용하는 경우 유형을 추론 할 수 있기 때문에

, 당신은 그것을 생략 할 수 있습니다 :

void SomeMethod<T>(T x, T y) where T : IComparable<T> { 
    Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y)); 
} 

따라서 사용이 간단 해집니다 :

SomeMethod(3, 4);   // instead of SomeMethod<int>(3, 4); 
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two"); 

일반적인 유형의 경우 매개 변수가 메서드 서명에 사용되지 않으면 형식 추론이 불가능합니다.

var emptySequence = Enumerable.Empty<int>(); 
1

가장 좋은 이유는 제네릭 형식이 특정 형식 (또는 하위 클래스/구현 자)인지 확인하기 위해 "where"키워드를 사용하여 형식 안정성입니다. "typeof"를 사용하면 무엇이든 보낼 수 있습니다.

관련 문제