Подтвердить что ты не робот

Инициализация внутреннего класса с помощью частного конструктора

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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, который содержит этот тип.

Ответ 2

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

Я настоятельно призываю вас не пытаться этого. 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"});
    }
}

Ответ 3

Если это 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.

Ответ 5

Используйте класс Activator для его создания

Activator.CreateInstance(myType, true);