Как создать экземпляр класса, который имеет только частный конструктор без параметров в Silverlight?

Я работаю над запросом функции для построителя тестовых данных .NET. Мне нужно создавать экземпляры классов, которые имеют только частные конструкторы без параметров.

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

public class MyClass()
{
    private MyClass(){}
}

Для большинства других классов я использую следующий код:

(T)Activator.CreateInstance(typeof(T), true)

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

(T)FormatterServices.GetUninitializedObject(typeof(T))

К сожалению, у меня также есть требование, чтобы эта работа работала в Silverlight, и, к сожалению, Silverlight в настоящее время не содержит System.Runtime.Serialization.FormatterServices.

Кто-нибудь знает что-нибудь в реализации Silverlight, что позволило бы мне обойти это? Если это не удастся, знает ли кто-нибудь, как я могу реализовать мою собственную версию этого метода?


person mezoid    schedule 24.09.2010    source источник


Ответы (3)


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

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

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

person Jon Skeet    schedule 24.09.2010
comment
Это для классов .Net в целом или только для Silverlight? Однако, хотя я согласен с тем, что я бы не стал делать это для создания экземпляров классов в нормальном производственном коде, я думал, что это должно быть нормально, если созданный мной инструмент используется для создания экземпляров простых объектов poco, которые будут использоваться в модульных тестах. Я добавлю более подробную информацию о классе, который я пытаюсь создать, на всякий случай, если это имеет значение. - person mezoid; 24.09.2010
comment
@mezoid: В общем. Если вы начинаете делать то, от чего автор класса явно пытался помешать вам, вы просто приглашаете что-то пойти не так. - person Jon Skeet; 24.09.2010
comment
хорошая точка зрения! так что мне следует вообще избегать использования FormatterServices.GetUninitializedObject? Каков основной вариант использования этого метода? Описание MSDN не очень подробное ... - person mezoid; 24.09.2010
comment
@mezoid: я считаю, что он в основном используется внутри для сериализации. Я бы избегал этого, если у вас нет очень специализированной цели, такой как сериализация. - person Jon Skeet; 24.09.2010
comment
Большое спасибо за ваш ответ, Джон, это действительно помогло мне усомниться в моем дизайне. Оказывается, (T) Activator.CreateInstance (typeof (T), true) смог создать нужный мне класс. Смотрите мой ответ ниже ... - person mezoid; 27.09.2010
comment
@mezoid: Я рад, что это сработало для вас, но все равно немного воняет ... Думаю, я бы предпочел предоставить какой-то фабричный метод для каждого типа. Очевидно, вы лучше знаете свой контекст. - person Jon Skeet; 27.09.2010

Оказывается, ответ был прямо передо мной.

Если у вас есть класс, определенный следующим образом:

public class MyClass
{
    private MyClass(){}
}

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

(T)Activator.CreateInstance(typeof(T), true)

Дополнительный параметр true создает экземпляр с использованием конструктора по умолчанию для типа типа .

Оказывается, мне вообще не нужно было использовать FormatterServices.GetUninitializedObject.

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

На данный момент мое решение - отказаться от использования FormatterServices и просто разрешить генерирование исключения, если что-то пойдет не так с созданием типа.

В настоящее время, насколько я могу судить, с помощью (T) Activator.CreateInstance (typeof (T), true) я смогу построить большинство классов, с которыми я столкнулся, за исключением следующего:

public MyClass()
{
    int a;
    private MyClass(int a)
    {
        this.a = a;
    }
}

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

int argA = 100; 
Type type = typeof(MyClass);

ConstructorInfo c = type.GetConstructor(BindingFlags.NonPublic 
| BindingFlags.Instance, null, new Type[] { typeof(int) }, null);

MyClass o = (MyClass)c.Invoke(new Object[] { argA });

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

person mezoid    schedule 27.09.2010

Вы можете сделать это с помощью отражения, но

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

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

Вот код:

var privateConstructors = typeof(MyClass).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var constr in privateConstructors)
{
    var obj = constr.Invoke(new object[0]);
    return;
}
throw new Exception("private constructor not found");
person Francesco De Vittori    schedule 24.09.2010