Question

I want to create some instances of classes via Activator.CreateInstance(...). All classes inherit same abstract class. The constructor has one parameter.

Classes and constructors should not be public.

This is what I want in code (but not get):

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);
    }
}

But this throws an Exception Constructor on type 'Foo' not found.

When I change constructor of FooAbstract and Foo to public all will be fine (classes stay internal!).

So I can understood that Activator.CreateInstance(...) needs public access (he comes from outside the package), but why is this possible with remaining internal classes?

Until now I thought that when class is internal and constructor is public it would be the same as class is internal and constructor is also internal (to kind of hierarchic access layers) ... but this seems to be wrong!

Can somebody help me to understand what happened here - why public constructors in internal classes do work?

Was it helpful?

Solution

You need to specify the BindingFlags for reflection to find it:

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

Now, in this case you do need to build an object[] because it's not a params.

As Matthew Watson stated, I should clarify the way reflection works. And maybe more specifically modifiers. They [modifiers] aren't built for real protection. They are built to determine the API that's available when you're using the types.

Reflection however, works directly off the modifier. If it's public - then with reflection it's public. It doesn't matter the hierarchy. Remember, reflection can actually access private members. I know, I've had to hack a few things like that before.

Further, constructors don't inherit the modifier of the class. The default constructor - that's generated by the compiler if you don't define it - is always public.

OTHER TIPS

The activator uses reflection to invoke the proper instance of the constructor. It likely by default is looking only for public class members. As stated by neoistheone you can change the way it is looking for the constructor by setting flags on the activator method call. The decompiled code for that method looks like this.

[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 is a reflected type there is a stack overflow question about it here: What's the difference between System.Type and System.RuntimeType in C#?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top