Создание экземпляра типа без конструктора по умолчанию в C# с использованием отражения

В качестве примера возьмем следующий класс:

class Sometype
{
    int someValue;

    public Sometype(int someValue)
    {
        this.someValue = someValue;
    }
}

Затем я хочу создать экземпляр этого типа, используя отражение:

Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);

Обычно это работает, однако, поскольку SomeType не определил конструктор без параметров, вызов Activator.CreateInstance вызовет исключение типа MissingMethodException с сообщением «Для этого объекта не определен конструктор без параметров.». Есть ли альтернативный способ создания экземпляра этого типа? Было бы отстойно добавлять конструкторы без параметров ко всем моим классам.

FormatterServices.GetUninitializedObject не позволяет создавать неинициализированную строку. Вы можете получить исключение: System.ArgumentException: Uninitialized Strings cannot be created. Имейте это в виду.
Bartosz Pierzchlewicz 15.01.2010 11:14

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

Aistina 15.01.2010 18:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
100
2
89 326
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

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

FormatterServices.GetUninitializedObject() создаст экземпляр без вызова конструктора. Я нашел этот класс, используя Отражатель и покопавшись в некоторых основных классах сериализации .Net.

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;

namespace NoConstructorThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass)); //does not call ctor
            myClass.One = 1;
            Console.WriteLine(myClass.One); //write "1"
            Console.ReadKey();
        }
    }

    public class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("MyClass ctor called.");
        }

        public int One
        {
            get;
            set;
        }
    }
}

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

Aistina 24.12.2008 05:04

Значение по умолчанию для каждого типа будет значением по умолчанию. Таким образом, объекты будут иметь значение null, int 0 и т. д. Я думаю, что любая инициализация на уровне класса происходит, но конструктор не запускается.

Jason Jackson 24.12.2008 06:59

@JSBangs, отстой, вы даете вполне законный ответ. Ваш комментарий и другой ответ на самом деле не затрагивают заданный вопрос. Если вы чувствуете, что у вас есть лучший ответ, дайте его. Но предоставленный мной ответ подчеркивает, как использовать документированный класс так же, как другие классы сериализации используют этот код.

Jason Jackson 21.11.2010 23:43

@JSBangs FormatterServices (msdn.microsoft.com/en-us/library/…) не недокументирован.

Autodidact 28.12.2010 09:53

@Cal - Да, это очень мощная функция, и ее следует использовать с осторожностью. Я только Когда-либо использовал эту функцию в одном месте в моем коде за последние 3 года с тех пор, как я опубликовал это.

Jason Jackson 27.10.2011 01:27

Как я могу вызвать все конструкторы по умолчанию (и базу для унаследованных) позже?

Wobbles 23.11.2019 16:50

Используйте эту перегрузку метода CreateInstance:

public static Object CreateInstance(
    Type type,
    params Object[] args
)

Creates an instance of the specified type using the constructor that best matches the specified parameters.

См .: http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx

Это решение упрощает проблему. Что делать, если я не знаю свой тип и говорю «просто создайте объект типа в этой переменной типа»?

kamii 20.04.2017 00:59

Хорошие ответы, но непригодные для использования на компактной платформе dot net. Вот решение, которое будет работать на CF.Net ...

class Test
{
    int _myInt;

    public Test(int myInt)
    {
        _myInt = myInt;
    }

    public override string ToString()
    {
        return "My int = " + _myInt.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var ctor = typeof(Test).GetConstructor(new Type[] { typeof(int) });
        var obj = ctor.Invoke(new object[] { 10 });
        Console.WriteLine(obj);
    }
}

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

Rory MacLeod 18.02.2010 21:56

Вы можете создать объект без вызова конструкторов, если вы пишете собственные сериализаторы.

Autodidact 21.02.2010 13:59

Да, это точный сценарий использования, для которого был задан вопрос :)

Aistina 14.05.2010 20:17

@Aistina Возможно, вы могли бы добавить эту информацию к вопросу? Большинство людей были бы против создания объектов без обращения к своим ctors и потратили бы время, чтобы поспорить с вами по этому поводу, но ваш вариант использования действительно оправдывает это, поэтому я думаю, что это очень актуально для самого вопроса.

julealgon 24.10.2013 19:23

Когда я проверенный производительность (T)FormatterServices.GetUninitializedObject(typeof(T)) была медленнее. В то же время скомпилированные выражения дадут вам значительное повышение скорости, хотя они работают только для типов с конструктором по умолчанию. Я использовал гибридный подход:

public static class New<T>
{
    public static readonly Func<T> Instance = Creator();

    static Func<T> Creator()
    {
        Type t = typeof(T);
        if (t == typeof(string))
            return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();

        if (t.HasDefaultConstructor())
            return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();

        return () => (T)FormatterServices.GetUninitializedObject(t);
    }
}

public static bool HasDefaultConstructor(this Type t)
{
    return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}

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

Назови это:

MyType me = New<MyType>.Instance();

Обратите внимание, что (T)FormatterServices.GetUninitializedObject(t) не сможет выполнить строку. Следовательно, для возврата пустой строки предусмотрена специальная обработка строки.

Странно, как взгляд на одну строчку чьего-то кода может спасти день. Спасибо, сэр! Причины производительности привели меня к вашему сообщению, и трюк сделан :) Классы FormatterServices и Activator неэффективны по сравнению с скомпилированными выражениями, как жаль, что активаторы повсюду.

jmodrak 17.11.2013 10:19

@nawfal Что касается вашей специальной обработки строки, я знаю, что она не удалась бы для строки без этой специальной обработки, но я просто хочу знать: будет ли она работать для других типов все?

Sнаđошƒаӽ 18.07.2018 19:59

@ Sнаđошƒаӽ к сожалению нет. Данный пример является базовым, и .NET имеет много разных типов. Например, подумайте, если вы передадите тип делегата, как вы предоставите ему экземпляр? Или иначе, если конструктор выдает, что вы можете с этим поделать? Много разных способов справиться с этим. С тех пор, как я ответил на это, обновлено, чтобы обрабатывать гораздо больше сценариев в моей библиотеке. Он пока нигде не опубликован.

nawfal 18.07.2018 21:29

Другие вопросы по теме