2009-08-15 5 views
4

기본 클래스가 FooParent인데 많은 양의 FooChildren이 있다고 가정 해 보겠습니다. 런타임에는 FooChildren 중 하나의 인스턴스를 만들어야합니다. 어떻게하면 좋을까요? 거대한지도를 만들고 (대표자를 사용하는 것) 또는 거대한 switch/case 성명을 만들 수 있다는 것을 알았지 만 그것은 조금 엉성한 것 같습니다. PHP와 같은 것으로, 다음과 같이 클래스를 동적으로 쉽게 만들 수 있습니다..NET에서의 동적 클래스 초기화

$className="FooClass"; 
$myNewFooClass=new $className; //makes a new instance of FooClass 

(리플렉션을 사용하여이를 수행 할 수도 있음)

.NET에는 이와 유사한 기능이 있습니까? 리플렉션은 옵션이며 성능에 대한 벌칙이 있습니까? 그렇지 않은 경우 어떤 옵션이 있습니까?

클래스 유형은 JSON 요청에 의해 결정됩니다. 변수는 내가 원하는 것일 수 있습니다. 열거 형을 원한다면 정수가 될 수도 있고 전체 클래스 이름이 될 수도 있습니다. 나는 아직 그것을 만들지 않았으므로 나는 결정되지 않았다.

+0

"Activator.CreateInstance"를 찾으십시오. –

+0

클래스에는 항상 매개 변수없는 생성자가 있습니까? –

답변

8

정말 원한다면 반성으로 할 수 있지만 실적이 저하 될 수 있습니다. 그들이 중요한지 여부는 정확한 상황에 달려 있습니다.

정확히 무엇을하고 싶은지에 따라 스위치/케이스 문이나지도를 사용하는 것이 좋습니다. 특히 여러분이 구성하는 유형에 따라 다른 생성자에 다른 인수를 전달해야하는 경우 유용합니다. 리플렉션을 통해 수행하면 이미 다른 유형의 특수 케이스가 될 수 있다는 점에서 약간의 고통이됩니다.


편집 : 좋아요, 이제 매개 변수없는 생성자가 있다는 것을 알았습니다. 이 경우, (그들은 같은 공간에있는 모든하는 경우) JSON 쉽게 네임 스페이스없이 클래스 이름을 포함 할 수 및 방법은 다음과 같이 볼 수 있습니다 :

public FooParent CreateFoo(string name) 
{ 
    if (name == null) 
    { 
     throw new ArgumentNullException("name"); 
    } 
    string fullName = "Some.NameSpace." + name; 
    // This is assuming that the type will be in the same assembly 
    // as the call. If that's not the case, we can look at that later. 
    Type type = Type.GetType(fullName); 
    if (type == null) 
    { 
     throw new ArgumentException("No such type: " + type); 
    } 
    if (!typeof(FooParent).IsAssignableFrom(type)) 
    { 
     throw new ArgumentException("Type " + type + 
            " is not compatible with FooParent."); 
    } 
    return (FooParent) Activator.CreateInstance(type); 
} 

당신이를 결정합니까 사용할 이름? 당신은, 그냥 내가 아닌 (이 실제 혜택이 있는지 아니에요을 작성하는 데

public FooParent CreateFoo(string name) 
{ 
    switch (name) 
    { 
     case "Foo1":  return new Foo1(); 
     case "Foo2":  return new Foo2(); 
     case "Foo3":  return new Foo3(); 
     case "Foo4":  return new Foo4(); 
     case "FooChild1": return new FooChild1(); 
     default: 
      throw new ArgumentException("Unknown Foo class: " + name); 
    } 
} 

마음 :이 곳에서 전달 있다면 멀리 조금 표준에서 포맷 할 때, 스위치 문은 매우 간단 할 수있다 성능)을 Type.GetType(name) 이상으로 입력 한 다음 Activator.CreateInstance(type)을 사용합니다.

발신자는 전달할 클래스 이름을 어떻게 알 수 있습니까? 윌은 분명히 역동적일까요? 제네릭을 사용할 수 있습니까? 상황에 대해 더 많이 이야기할수록 우리가 더 도움이 될 수 있습니다.

+0

나는 조금 더 명확하게되기를 바란다. – ryeguy

+0

예, 클래스에는 항상 paramaterless 생성자가 있습니다. – ryeguy

2
yourvar = Activator.CreateInstance(Type.GetType("foo.bar.Baz")); 
3

모든 FooChildren에 매개 변수없는 생성자가있는 한 반영 할 수 있습니다. 당신이 실제로 유형에 대한 참조를 가지고 있지 않으며, 당신이 가진 모든 클래스의 이름을 문자열 인 경우

Activator.CreateInstance<FooChildType>(); 

, 당신은 할 수 있습니다 :

Activator.CreateInstance("FooChildClassName", "Fully.Qualified.AssemblyName"); 

는 성능 저하가 리플렉션을 사용했지만 가장 간단한 해결책으로 밝혀지면 성능에 문제가있을 수 있습니다.

0

성능에 신경 쓰면 다른 옵션이 있습니다. 클래스 유형을 얻으려면

Type yourType = Type.GetType("FooClass"); 

을 사용하십시오. 이제 생성자에 대한 생성자 정보를 얻으려면

ConstructorInfo ctor = yourType.GetConstructor(new Type[0]); 

을 사용할 수 있습니다. 기본 생성자를 원하지 않으면 생성자에 전달할 유형의 배열을 전달하십시오. 이제 다음과 같이 생성자를 사용할 수 있습니다.

object instanceOfFooClass = ctor.Invoke(new object[0]); 

처음 두 단계는 한 번만 실행하면됩니다. 추후 사용을 위해 "ctor"를 저장할 수 있습니다. Activator.CreateInstance를 호출하는 것이 빠릅니다.