Создание внутреннего класса с помощью частного конструктора - PullRequest
25 голосов
/ 07 января 2010

Я пытаюсь использовать отражение, чтобы создать экземпляр класса. Но он запечатан внутри и имеет частный конструктор. Интересно, как я могу его инициировать, и, как часть его структуры, я могу использовать только отражение, чтобы убрать его?

internal sealed class ABC
{
    private ABC(string password){}
    public static ABC Create(string password){};
}

Добавлено: System.ServiceModel.Channels.SelfSignedCertificate - это внутренний класс, который я пытаюсь использовать

Ответы [ 5 ]

25 голосов
/ 07 января 2010

EDIT: я не заметил, что вы упомянули, что тип, который вы пытаетесь инициализировать, является частью .NET Framework. Я думал, что это был один из ваших собственных типов, на который просто ссылались из других источников.

Я настоятельно призываю вас не пытаться сделать это . Microsoft может свободно изменять или удалять внутренние классы между выпусками платформы - ваш код будет невероятно хрупким, если вы будете полагаться на детали реализации, подобные этой.

Измените свой дизайн, чтобы избежать необходимости делать это.


Оригинальный ответ:

Да, вам придется использовать отражение - вот так:

using System;
using System.Reflection;

internal sealed class ABC
{
    private ABC(string password)
    {
        Console.WriteLine("Constructor called");
    }
}

public class Test
{
    static void Main()
    {
        ConstructorInfo ctor = typeof(ABC).GetConstructors
            (BindingFlags.Instance | BindingFlags.NonPublic)[0];

        ABC abc = (ABC) ctor.Invoke(new object[] { "test" });
    }
}

Обратите внимание, что для такого изменения модификаторов доступа требуется разрешение ReflectionPermissionFlag.MemberAccess. Если вы знаете, что будет статический метод с именем Create, вам лучше вызвать , чем , с помощью отражения:

using System;
using System.Reflection;

internal sealed class ABC
{
    private ABC(string password)
    {
        Console.WriteLine("Constructor called");
    }

    public static ABC Create(string password)
    {
        return new ABC(password);
    }
}

public class Test
{
    static void Main()
    {
        MethodInfo method = typeof(ABC).GetMethod("Create",
            BindingFlags.Static | BindingFlags.Public);

        ABC abc = (ABC) method.Invoke(null, new object[]{"test"});
    }
}
19 голосов
/ 07 января 2010

Прежде всего, сам факт, что это внутреннее, означает, что вы не должны делать то, что хотите.

Вы должны серьезно попытаться найти альтернативный путь к тому, чего вы хотите достичь.

К сожалению, вы не говорите нам о том, чего хотите достичь, а только о следующем шаге, который, как вы думаете, вы хотите сделать, поэтому я могу вам помочь.

Этот код будет работать и получать доступ к общедоступному статическому методу:

Type t = typeof(SomeOtherTypeInSameAssembly)
    .Assembly.GetType("ClassLibrary1.ABC");
MethodInfo method = t.GetMethod("Create",
    BindingFlags.Public | BindingFlags.Static, null,
    new Type[] { typeof(String) },
    new ParameterModifier[0]);
Object o = method.Invoke(null, new Object[] { "test" });

Обратите внимание, что это зависит от наличия доступа к другому типу в той же сборке, которая является общедоступной. Если у вас его нет, вам нужно получить объект Assembly, который содержит тип.

3 голосов
/ 07 января 2010

Если это internal для сборки, которая не принадлежит вам, и конструктор помечен как private, автор сборки очень старается удержать вас от создания объекта.

Ниже очень плохо, потому что вы полагаетесь на закрытые уроки и методы, которые могут измениться без предварительного уведомления.

Добавлено: System.ServiceModel.Channels.SelfSignedCertificate - это класс internal, который я пытаюсь использовать

Не делайте этого . Структура может измениться под вами в мгновение ока, разрушая ваш код и всю вашу тяжелую работу.

Тем не менее, вы могли бы сделать это:

MethodInfo method = Type.GetType(assemblyQualifiedName).GetMethod("Create");
ABC o = (ABC)method.Invoke(null, new[] { "test" });

Это вызывает метод static Create. Другой вариант -

MethodInfo method = Type.GetType(assemblyQualifiedName).GetConstructor(
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null,
                        new[] { typeof(string) },
                        null
                    );
ABC o = (ABC)method.Invoke(new[] { "test" });

, который использует отражение для загрузки конструктора, который принимает string в качестве параметра.

Простой способ получить квалифицированное для сборки имя:

string name = typeof(somePublicType).Assembly.GetType("Namespace.ABC");

, где somePublicType - тип, который является общедоступным и находится в той же сборке, что и ABC.

0 голосов
/ 07 января 2010

Используйте класс Activator, чтобы создать его экземпляр

Activator.CreateInstance(myType, true);
0 голосов
/ 07 января 2010

Вы не можете создавать экземпляры классов с закрытыми конструкторами, если это не вложенный класс.

http://msdn.microsoft.com/en-us/library/kcfb85a6%28VS.71%29.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...