Как сослаться на тип частного класса из атрибута уровня сборки? - PullRequest
3 голосов
/ 30 августа 2011

Я определил класс атрибута уровня сборки FooAttribute следующим образом:

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

и использую его для привязки id к классам, например:

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

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

Все это прекрасно работает.Но что, если мне нужно как-то ссылаться на закрытый класс Mystery, определенный в MyClass?Это вообще возможно?Попытка ссылки на нее из директивы верхнего уровня [assembly: ...] не работает, так как тип не является общедоступным:

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

И попытка поместить директиву [assembly: ...] в MyClass так, чтобыон может видеть, что Mystery недопустимо, так как [assembly: ...] должен быть определен на верхнем уровне:

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

Существует способ получить доступ к типам internal извне сборки, объявив пользователя друг сборки, но как насчет ссылок на частные типы внутри сборки?Я думаю, что это невозможно, и мне просто нужно было бы объявить Mystery как internal, но я хочу быть уверенным, что не упустил некоторые тонкости.

Ответы [ 2 ]

4 голосов
/ 30 августа 2011

Сделать это internal (что вы уже заявляете, что не хотите делать) - это подход с наименьшими усилиями.Для большей части кода, позволяя MyClass выставлять (через статическое свойство) экземпляр type (т.е. public static Type MysteryType { get { return typeof(Mystery); } } будет работать, но это не будет работать с атрибутом(можно использовать только константные значения нескольких базовых типов).

Единственная альтернатива internal состоит в том, чтобы кодировать его как строковый литерал , (то есть [Foo("Bar.MyClass+Mystery")]) и используйте typeof(MyClass).Assembly.GetType(fullName) - но тогда вы потеряете проверку компилятора, которую обычно обеспечивает typeof (обратите внимание также на +, который среда выполнения использует для представления вложенных типов, а не ., который является представлением C #)

Лично я бы просто сделал это internal.

2 голосов
/ 30 августа 2011

Ваши утверждения в последних абзацах верны.Возможны следующие варианты:

  • Сделать вложенный класс внутренним, чтобы включить typeof

или

  • Добавить конструктор для FooAttribute, который принимает полное имя типа частного вложенного класса, а затем использует отражение, чтобы получить System.Type, представляющий его.

Например:

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

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

использование:

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

namespace Foo
{
    public class Bar
    {
        private class Baz
        {
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...