How to reference the type of a private class from an assembly-level attribute?
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
, defi开发者_运维百科ned 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.
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
.
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 aSystem.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
{
}
}
}
精彩评论