c# generic method




템플릿 형식의 C#generic new()에 인수 전달 (9)

'Reflection'답변 (개인적으로 가장 좋은 대답이라고 생각하는)을 게시하는 데 아무도 귀찮은 사람이 아니기 때문에 여기에 간다.

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       Type classType = typeof(T);
       ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { listItem.GetType() });
       T classInstance = (T)classConstructor.Invoke(new object[] { listItem });

       tabListItems.Add(classInstance);
   } 
   ...
}

편집 :이 대답은 .NET 3.5의 Activator.CreateInstance로 인해 더 이상 사용되지 않지만 이전 .NET 버전에서는 여전히 유용합니다.

목록에 추가 할 때 해당 생성자를 통해 형식 T의 새 개체를 만들려고합니다.

컴파일 오류가 발생합니다. 오류 메시지는 다음과 같습니다.

'T': 변수의 인스턴스를 만들 때 인수를 제공 할 수 없습니다.

하지만 클래스에는 생성자 인수가 있습니다! 이 작품을 어떻게 만들 수 있습니까?

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T(listItem)); // error here.
   } 
   ...
}

.NET 3.5에서 activator 클래스를 사용할 수 있습니다.

(T)Activator.CreateInstance(typeof(T), args)

나는 "T 형 매개 변수의 인스턴스를 생성 할 때 인수를 제공 할 수 없다"라는 오류가 발생하여이를 수행해야했습니다.

var x = Activator.CreateInstance(typeof(T), args) as T;

나는 새로운 생성자를 가진 객체만을 허용하기 위해 where 문으로 T를 제약해야한다고 생각한다.

이제는 객체가없는 객체도 허용합니다.


사용하려는 클래스에 대한 액세스 권한이 있으면 내가 사용한이 접근 방식을 사용할 수 있습니다.

대체 작성자가있는 인터페이스를 만듭니다.

public interface ICreatable1Param
{
    void PopulateInstance(object Param);
}

빈 생성자로 클래스를 만들고이 메소드를 구현하십시오.

public class MyClass : ICreatable1Param
{
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        //populate the class here
    }
}

이제 일반적인 방법을 사용하십시오.

public void MyMethod<T>(...) where T : ICreatable1Param, new()
{
    //do stuff
    T newT = new T();
    T.PopulateInstance(Param);
}

액세스 권한이없는 경우 대상 클래스를 래핑하십시오.

public class MyClass : ICreatable1Param
{
    public WrappedClass WrappedInstance {get; private set; }
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        WrappedInstance = new WrappedClass(Param);
    }
}

생성자 매개 변수로 멤버 필드 또는 속성을 초기화하려는 경우 C #> = 3에서 매우 쉽게 수행 할 수 있습니다.

public static string GetAllItems<T>(...) where T : InterfaceOrBaseClass, new() 
{ 
   ... 
   List<T> tabListItems = new List<T>(); 
   foreach (ListItem listItem in listCollection)  
   { 
       tabListItems.Add(new T{ BaseMemberItem = listItem }); // No error, BaseMemberItem owns to InterfaceOrBaseClass. 
   }  
   ... 
} 

이것은 게리 셔틀 (Garry Shutler)이 말한 것과 같은 것이지만, 나는 덧붙여 말하면 좋겠다.

물론 필드 값을 설정하는 것보다 더 많은 일을 할 수있는 속성 트릭을 사용할 수 있습니다. "set ()"속성은 관련 필드를 설정하는 데 필요한 모든 처리를 트리거 할 수 있으며 개체가 사용되기 전에 전체 초기화가 수행되는지 확인하고 전체 구성을 시뮬레이션하는 등의 개체 자체에 대한 다른 필요성을 트리거 할 수 있습니다. 예, 그것은 추악한 해결 방법이지만, M $의 새로운 () 제한을 극복합니다.

계획된 구멍이나 우발적 인 부작용이 있다면 확신 할 수 없지만 작동합니다.

M $ 사람들이 언어에 새로운 기능을 추가하고 전체 부작용 분석을 수행하지 않는 것처럼 보이는 것은 매우 재미 있습니다. 모든 일반적인 것은 이것에 대한 좋은 증거입니다 ...


이건 일종의 운이 좋고, 내가 일종의 운이 좋다는 말을하면 반란을 의미 할 수도 있지만 매개 변수화 된 유형에 빈 생성자를 제공 할 수 있다고 가정하면 다음을 수행합니다.

public static T GetTInstance<T>() where T: new()
{
    var constructorTypeSignature = new Type[] {typeof (object)};
    var constructorParameters = new object[] {"Create a T"};
    return (T) new T().GetType().GetConstructor(constructorTypeSignature).Invoke(constructorParameters);
}

인수를 사용하여 매개 변수화 된 유형의 객체를 효과적으로 만들 수 있습니다. 이 경우에는 원하는 생성자에 type object 의 단일 인수가 있다고 가정 object . 우리는 제약 조건이 허용 된 빈 생성자를 사용하여 T의 더미 인스턴스를 만든 다음 리플렉션을 사용하여 다른 생성자 중 하나를 가져옵니다.


컴파일러가 T가 기본 생성자를 제공한다는 것을 알 수 있도록 T : new ()를 추가해야합니다.

public static string GetAllItems<T>(...) where T: new()

개체 이니셜 라이저

매개 변수가있는 생성자가 속성 설정 이외의 작업을 수행하지 않는 경우 C # 3 이상에서는 생성자를 호출하는 대신 개체 이니셜 라이저를 사용하여이 작업을 수행 할 수 있습니다 (위에서 언급 한 것처럼 불가능 함).

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
   } 
   ...
}

이것을 사용하면 항상 생성자 논리를 기본 (빈) 생성자에 배치 할 수 있습니다.

Activator.CreateInstance ()

또는 Activator.CreateInstance() 과 같이 호출 할 수 있습니다.

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
        object[] args = new object[] { listItem };
        tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
   } 
   ...
}

Activator.CreateInstance는 실행 속도가 최우선이고 다른 옵션을 유지 관리 할 수 ​​있으면 피할 수있는 성능 오버 헤드 가있을 수 있습니다.





new-operator