2013-10-15 5 views
7

Activator.CreateInstance(...)을 통해 클래스의 인스턴스를 만들고 싶습니다. 모든 클래스는 동일한 추상 클래스를 상속합니다. 생성자에는 하나의 매개 변수가 있습니다.내부 클래스 및 공용 생성자 - Activator.CreateInstance와 함께 작동하는 이유는 무엇입니까?

클래스 및 생성자 은 (는)이 공개되어서는 안됩니다.

internal abstract class FooAbstract 
{ 
    protected Bar MyProperty { get; set; } 

    // Constructor is only need in concreat classes of FooAbstract 
    protected FooAbstract(Bar barProperty) 
    { 
     MyProperty = barProperty; 
    } 
} 

internal class Foo : FooAbstract 
{ 
    // Internal is enough, public is not necessary 
    internal Foo(Bar barProperty) 
     : base(barProperty) 
    { 
} 

// Many more Foo´s ... 

internal class Creator() 
{ 
    private object CreateAFoo<T>() where T : FooAbstract 
    { 
     T someFoo = (T)Activator.CreateInstance(typeof(T), barProperty); 
    } 
} 

을하지만이 예외 Constructor on type 'Foo' not found을 던졌습니다 :

이것은 내가 코드를 원하는 것입니다 (하지만하지). 내가 publicFooAbstractFoo의 생성자를 변경하는 경우

모두가 잘 될 것입니다 (클래스 internal을 유지!).

따라서 Activator.CreateInstance(...)은 공개 액세스가 필요합니다 (그는 패키지 외부에서 제공됨).하지만 내부 클래스가 남아있는 이유는 무엇입니까?

는 지금까지 내가 클래스는 내부 때생성자 클래스는 내부에생성자 (계층 적 액세스 레이어의 종류 또한 내부와 같이이 같은 것 공개 생각) ...하지만 이것은 잘못된 것 같습니다!

누군가 여기서 내가 무슨 일이 있었는지 이해할 수있게 도와 줄 수 있습니까? 왜 내부 수업의 공공 생성자가 효과가 있습니까?

+1

이것은 아주 좋은 질문입니다 - 내가 설명을보고 싶어요. 클래스가 내부 클래스 인 경우 생성자 중 하나라도 public으로 표시 되어도 내부 클래스가됩니다. 따라서, 당신이 말했듯이, Activate.CreateInstance()에 영향을 미치지 않아야합니다. –

답변

10

당신은 그것을 찾기 위해 반사의 BindingFlags를 지정해야합니다

(T)Activator.CreateInstance(typeof(T), 
    BindingFlags.Instance | BindingFlags.NonPublic, 
    null 
    new object[] { barProperty }, 
    null); 

자,이 경우에 당신이 그것은 params 아니다 때문에 object[]를 구축 필요합니까.

매튜 왓슨 (Matthew Watson)이 말했듯이 나는 반사 작용의 방식을 분명히해야합니다. 그리고 좀 더 구체적으로 수식어를 사용합니다. 그들은 [수정 자]는 실제 보호를 위해 만들어지지 않았습니다. 유형을 사용할 때 사용할 수있는 API를 결정하기 위해 API가 작성되었습니다.

반사 그러나 수정 자 해제 작동합니다. 그것이 public 인 경우 - 반향은 public입니다. 계층 구조는 중요하지 않습니다. 리플렉션은 실제로 private 회원에 액세스 할 수 있습니다. 나도 알아, 나는 그 전에 몇 가지 해킹했다.

또한 생성자는 class의 한정자를 상속하지 않습니다. 정의하지 않으면 컴파일러에서 생성되는 기본 생성자는 이고 항상public입니다.

+1

네, 어떻게 할 수 있습니까?하지만 실제 질문에 대답하지 않습니다. 따라서 생성자를 public으로 변경하면 문제가 해결됩니다. 내부 클래스의 생성자는 public으로 표시되어 있는지 여부에 관계없이 항상 내부 클래스 여야합니다. –

+0

@MatthewWatson, 실제로 리플렉션은 한정자에서 작동합니다. 그래서 생성자가'public'으로 만들어 졌기 때문에'public'입니다. 수식어는 리플렉션 또는 실제 * 보호를 위해 제작되지 않았습니다. 리플렉션은 'private'멤버에 액세스 할 수 있습니다. –

+2

아, 알았어. 따라서 생성자는 비 - 반사 사용을위한 "내부"이고 반사 사용을위한 "공개"인 것으로 간주됩니다. 흥미 롭다. (그리고 아마도 매우 혼란 스럽다.) 어쨌든 대답은 OP가 실제로 묻는 질문이기 때문에 답으로 써야한다. –

1

활성자는 활성을 사용하여 생성자의 적절한 인스턴스를 호출합니다. 기본적으로 공개 클래스 멤버 만 찾고있을 가능성이 높습니다. neoistheone에 명시된 바와 같이 액티베이터 메서드 호출에 플래그를 설정하여 생성자를 찾는 방식을 변경할 수 있습니다. 해당 메소드의 디 컴파일 된 코드는 다음과 같습니다.

[SecuritySafeCritical] 
[MethodImpl(MethodImplOptions.NoInlining)] 
public static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes) 
{ 
    if (type == null) 
    { 
     throw new ArgumentNullException("type"); 
    } 
    if (type is TypeBuilder) 
    { 
     throw new NotSupportedException(Environment.GetResourceString("NotSupported_CreateInstanceWithTypeBuilder")); 
    } 
    if ((bindingAttr & (BindingFlags)255) == BindingFlags.Default) 
    { 
     bindingAttr |= (BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance); 
    } 
    if (activationAttributes != null && activationAttributes.Length > 0) 
    { 
     if (!type.IsMarshalByRef) 
     { 
      throw new NotSupportedException(Environment.GetResourceString("NotSupported_ActivAttrOnNonMBR")); 
     } 
     if (!type.IsContextful && (activationAttributes.Length > 1 || !(activationAttributes[0] is UrlAttribute))) 
     { 
      throw new NotSupportedException(Environment.GetResourceString("NotSupported_NonUrlAttrOnMBR")); 
     } 
    } 
    RuntimeType runtimeType = type.UnderlyingSystemType as RuntimeType; 
    if (runtimeType == null) 
    { 
     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "type"); 
    } 
    StackCrawlMark stackCrawlMark = StackCrawlMark.LookForMyCaller; 
    return runtimeType.CreateInstanceImpl(bindingAttr, binder, args, culture, activationAttributes, ref stackCrawlMark); 
} 

RuntimeType이 여기에 대한 스택 오버 플로우 문제가 반사 유형 : What's the difference between System.Type and System.RuntimeType in C#?

+0

추가 정보 - 매우 흥미로운 감사합니다. +1. – Micha