Question

I have defined an assembly level attribute class FooAttribute like this:

namespace Bar
{
    [System.AttributeUsage (System.AttributeTargets.Assembly, AllowMultiple=true)]
    public sealed class FooAttribute : System.Attribute
    {
        public FooAttribute(string id, System.Type type)
        {
            // ...
        }
    }
}

and I use it to associate an id to classes, for instance:

[assembly: Bar.Foo ("MyClass", typeof (Bar.MyClass))]

namespace Bar
{
    public class MyClass
    {
        private class Mystery { }
    }
}

This all works fine. But what if I need to somehow reference the private class Mystery, defined in MyClass? Is this at all possible? Trying to reference it from the top-level [assembly: ...] directive does not work, as the type is not publicly visible:

[assembly: Bar.Foo ("Mystery", typeof (Bar.MyClass.Mystery))] // won't work

And trying to put the [assembly: ...] directive into MyClass in so that it could see Mystery is not legal, as [assembly: ...] must be defined at the top level:

namespace Bar
{
    class MyClass
    {
        [assembly: FooAttribute (...)] // won't work either
        ...
    }
}

There is a way to access internal types from outside of an assembly by declaring the user a friend of the assembly, but how about referencing private types inside an assembly? I guess it is not possible, and I just would have to declare Mystery to be internal instead, but I want to be sure I did not miss some subtlety.

Was it helpful?

Solution

Your assertions in your last paragraphs are correct. Your options would be to:

  • Make the nested class internal to enable typeof

or

  • Have an added constructor to FooAttribute which takes the fully qualified type name of the private nested class, and then uses reflection to get a System.Type representing it.

For instance:

public sealed class FooAttribute
{
    public FooAttribute(string id, string typeName)
    {
        var type = Type.GetType(typeName);

        // whatever the other ctor does with the System.Type...
    }
}

usage:

[assembly: Foo("Bar", typeof(Bar))]
[assembly: Foo("Baz", "Foo.Bar+Baz, MyAssembly")]

namespace Foo
{
    public class Bar
    {
        private class Baz
        {
        }
    }
}

OTHER TIPS

Making it internal (which you already state you don't want to do) is the least effort approach. For the majority of code, allowing MyClass to expose (via a static property) the type instance (i.e. public static Type MysteryType { get { return typeof(Mystery); } } would work, but that won't work from an attribute (only constant values of a few basic types can be used).

The only alternative to internal, then, is to code it as a string literal, (i.e. [Foo("Bar.MyClass+Mystery")]) and use typeof(MyClass).Assembly.GetType(fullName) - but then you lose the compiler validation that typeof normally provides. (note also the + that the runtime uses to represent nested types, not . which is the C# representation)

Personally, I'd just make it internal.

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