Создать экземпляр объекта без вызова конструктора?


В C# есть ли способ создать экземпляр класса без вызова его конструктора?

предположим, что класс является открытым и определяется в сторонней библиотеке, а конструктор является внутренним. Причины, по которым я хочу это сделать, сложны, но было бы полезно знать, возможно ли использовать какой-то хакерский c#.

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

11 62
c#

11 ответов:

Я не пробовал это, но есть метод, называемый FormatterServices.GetUninitializedObject, который используется во время десериализации.

замечания от MSDN говорит:

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

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

проверьте эти статьи:

Предотвращение Вывода Третьей Стороной: Часть 1

Предотвращение Вывода Третьей Стороной: Часть 2

Они как бы объясняют рассуждения.

вопреки тому, что многие считают, конструктор не имеет большого отношения к созданию экземпляра объекта вообще (довольно вводящий в заблуждение термин). Конструктор-это специальный метод, который может быть вызван после создания экземпляра объекта, чтобы позволить этому объекту правильно инициализировать себя. В C++ экземпляр объекта выделяет память для объекта, в .NET и Java он как выделяется, так и предварительно инициализируется значениями по умолчанию в зависимости от типа полей (0, null, false и т. д.). Затем время выполнения вызывает конструктор. Оператор new инкапсулирует эти два отдельных действия в то, что кажется одной операцией. Десериализация никогда не могла бы работать в .NET, если бы не было возможности создать экземпляр без использования конструктора. Тем не менее, так называемый тип ConstructorInfo действует как новый оператор и конструктор при вызове его Invoke(...) метод.

возможно, можно получить доступ к конструктору через отражение и вызвать его таким образом (но я не уверен, что он будет работать, так как конструктор является внутренним - вам придется его протестировать). В противном случае, насколько мне известно, вы не можете создать объект без вызова конструктора.

изменить: вы обновили свой вопрос, вы хотите построить класс без конструктора. Или вызовите по умолчанию "пустой конструктор".

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

предполагая, что ваш класс называется Foo:

using System.Reflection;

// If the constructor takes arguments, otherwise pass these as null
Type[] pTypes = new Type[1];
pTypes[0] = typeof(object);    
object[] argList = new object[1];
argList[0] = constructorArgs;

ConstructorInfo c = typeof(Foo).GetConstructor
    (BindingFlags.NonPublic |
     BindingFlags.Instance,
     null,
     pTypes,
     null);

Foo foo = 
    (Foo) c.Invoke(BindingFlags.NonPublic,
                   null, 
                   argList, 
                   Application.CurrentCulture);

некрасиво, но работает.

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

вы должны вызвать конструктор для создания объекта. Если нет доступных по вашему вкусу, возможно, вы могли бы использовать библиотеку перезаписи байтового кода, такую как Cecil проекта Mono. Он работает на Windows, а также Linux. Из некоторых демо, которые я видел, это выглядело довольно круто. Вы можете изменить уровни защиты методов и всевозможных сумасшедших вещей.

Если класс (и классы объектов, на которые он ссылается) Сериализуемы, вы можете создать глубокую копию путем сериализации с помощью BinaryFormatter, который выводит в поток памяти (создание массива байтов byte []), а затем десериализуется. Смотрите ответы на этот вопрос о преобразовании объекта в байтовый массив. (Но обратите внимание-сохранение массива байтов для использования позже / в другом месте, скорее всего, не будет работать. IOW не сохраняет массив байтов в файл или другую постоянную форму.)

посмотреть систему.Активатор.Функция CreateInstance.

тем не менее, платформа .Net framework пошла на уступки тому факту, что в действительности объекты фактически представлены в памяти. С некоторой креативностью можно создавать экземпляры типов значений без вызова их инициализаторов. Однако, если вы чувствуете, что вам нужно это сделать, вы, вероятно, делаете что-то неправильно.

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

кажется, что вы можете создать экземпляр класса без использования его конструкторов, присвоив значения его свойствам. Вот адрес, где находится практическое руководство в MSDN для этого типа экземпляраhttp://msdn.microsoft.com/en-us/library/bb397680.aspx.

кажется например, это метод, который не очень хорошо известен, потому что я столкнулся с ним в статье в CodeProject, а затем погуглил его и ничего не нашел об этом, а затем посетил домашнюю страницу MSDN, и был пост, который связал меня с этой точной темой. Таким образом, кажется, что это неизвестная тема, а не новая, потому что дата публикации CodeProject датируется маем 2008 года.

надеюсь, это поможет кому-то еще, что google это и сталкивается с этим вопросом.

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

конструктор и что создает объект. Ваш вопрос сродни "как я могу построить замок из песка, не формируя его как замок?- Ты не можешь ... все, что у тебя будет, - это куча песка.

самое близкое, что вы могли бы сделать, это выделить блок памяти того же размера, что и ваш объект:

byte[] fakeObject = new byte[sizeof(myStruct)];

(Примечание: даже это будет работать только в MyStruct является тип значения)