2008-11-17 3 views
62

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

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

ПРИМЕЧАНИЕ. Я конкретно не хочу называть какой-либо конструктор, поэтому использование отражения для доступа к внутреннему конструктору не является вариантом.

+3

Связанная с этим заметка и некоторые люди, как правило, не осознают заключается в том, что если вы создадите исключение во время построения, ваш объект все еще существует. Если он имеет финализатор, который все равно будет работать, вам нужно быть осторожным, чтобы не делать никаких предположений о том, что произошло в конструкторе. – meandmycode 2009-04-19 10:13:01

+0

Зачем вам это нужно? Если это просто любопытство, все в порядке. – nawfal 2014-01-02 13:07:11

+0

@nawfal WCF использует это для своего механизма сериализации, что является одной из причин его полезности в целом. Мой конкретный случай на самом деле играл вокруг существующей объектной модели (SharePoint OM), чтобы увидеть, можно ли обойти некоторые ошибки/ограничения для экспериментальных целей. Очень хриплый, но, опять же, экспериментальный. – 2014-01-09 01:36:27

ответ

78

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

Заметки из MSDN говорит:

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

0

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

+2

+1, я не знаю, почему кто-то проголосовал за этот правильный ответ. – StingyJack 2008-11-17 19:58:06

10

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

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

Preventing Third Party Derivation: Part 1

Preventing Third Party Derivation: Part 2

они отчасти объяснить рассуждения.

-1

См. Функцию System.Activator.CreateInstance.

+0

К сожалению, это правильный ответ. Вопрос был отредактирован после этой публикации. – nawfal 2014-01-02 13:04:03

0

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

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

Предполагая, что ваш класс называется 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); 

Уродливый, но работает.

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

+0

Разве вы не просто вызвали конструктор без создания экземпляра объекта? (например: полная противоположность того, что задает вопрос?) – 2008-11-17 19:52:01

0

То, что вы просите, является нарушением философии, на которой было разработано управляемое программирование. .Net Framework и C# построены с принципом, что, когда это возможно, объекты должны быть абстрагированы от их основной памяти. Объекты - это объекты, а не структурированный массив байтов. Вот почему вы не можете набрасывать объекты на void-указатели волей-неволей. Когда объекты абстрагируются от их основной памяти, принципиально недействительно предположить, что экземпляр объекта может существовать без вызова конструктора.

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

-3

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

Конструктор is Что создает объект. Ваш вопрос сродни:« Как я могу построить замок из песка без создания его как замка? »Вы не можете - все, что у вас будет, - это куча песок

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

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

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

0

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

5

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

-1

Я заметил «мертвость» предмета, но только для разъяснения читателям и окончательного ответа, который, возможно, не был возможен, когда вопрос был отправлен. Вот оно.

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

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

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

0

Если класс (и классы объектов, на которые он ссылается) является Serializable, вы можете создать глубокую копию путем сериализации с использованием BinaryFormatter, который выводится в MemoryStream (создание байтового байтового байта []), а затем десериализации.См. the answers to this question on converting an object to a byte array. (Но обратите внимание: сохранение байтового массива для использования позже или в другом месте, вероятно, не сработает. IOW не сохраняет массив байтов в файл или другую постоянную форму.)

Смежные вопросы