Вопрос по c#, reflection – C # с помощью отражения для создания структуры

13

В настоящее время я пишу код для сохранения общих объектов в XML с использованием отражения в c #.

Проблема заключается в том, что при чтении XML в некоторых объектах есть структуры, и я не могу понять, как инициализировать структуру. Для класса я могу использовать

ConstructorInfo constructor = SomeClass.GetConstructor(Type.EmptyTypes);

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

SomeStruct.TypeInitializer.Invoke(null)

но это создает исключение. Google не дает многообещающих хитов. Любая помощь будет оценена.

Ваш Ответ

3   ответа
16

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

Если структурыaren't неизменным, а затем убегать от них как можно быстрее, если вы можете ... но если вы абсолютноhave чтобы сделать это, затем используйтеActivator.CreateInstance(SomeClass), Вы должны быть очень осторожны, когда используете отражение для установки свойств или полей для типа значения, хотя - без этой заботы вы в конечном итоге создадите копию, измените значение этой копии и затем выбросите ее. яsuspect что если вы будете работать с коробочной версией, у вас все будет в порядке:

using System;

// Mutable structs - just say no...
public struct Foo
{
    public string Text { get; set; }
}

public class Test
{
    static void Main()
    {
        Type type = typeof(Foo);

        object value = Activator.CreateInstance(type);
        var property = type.GetProperty("Text");
        property.SetValue(value, "hello", null);

        Foo foo = (Foo) value;
        Console.WriteLine(foo.Text);
    }
}
Проблема в том, что прямо сейчас Activator.CreateInstance возвращает RuntimeType вместо типа, который я просил :( Что означает, что GetFields ничего не возвращает.
Что если структураbyte? Поскольку он неизменен, я не могу просто установить его значение после создания экземпляра. Как установить его значение с помощьюActivator?
@Marcel: Похоже, вы должны задать новый вопрос сMinimal, Complete, and Verifiable example.
Виноват; пытаясьfind проблема в типе, а не в этом. Я напишу вопрос, если не смогу разобраться.
Публикация в эпической теме ... Кроме того, upvote для краткого, чистого ответа.
4

CreateInstance не поможет вам со структурами без явно определенных конструкторов.

FormatterServices.GetUninitializedObject(Type type);

Это делает трюк с пустыми структурами.

0

Просто добавить - сimmutable Struct, вам, вероятно, придется выполнить сопоставление параметров с конструктором. К сожалению, это сложно, когда может быть несколько конструкций, особенно потому, что некоторые типы имеют отдельную статическую & quot; Создать & quot; метод вместо публичного конструктора. Ноassuming вы выполнили сопоставление, вы все еще можете использоватьActivator.CreateInstance:

    Type type = typeof(Padding); // just an example
    object[] args = new object[] {1,2,3,4};
    object obj = Activator.CreateInstance(type, args);

Однако код для выбора конструктора (в приведенном выше есть 3 ...) не прост. Вы могли бы сказать «выбери самое сложное» а затем попытаться сопоставить имена параметров с именами свойств (без учета регистра) ...

Наивный пример:

static void Main() {
    Dictionary<string, object> propertyBag =
        new Dictionary<string, object>();
    // these are the values from your xml
    propertyBag["Left"] = 1;
    propertyBag["Top"] = 2;
    propertyBag["Right"] = 3;
    propertyBag["Bottom"] = 4;
    // the type to create
    Type type = typeof(Padding);

    object obj = CreateObject(type, propertyBag);

}
static object CreateObject(Type type, IDictionary<string,object> propertyBag)
{
    ConstructorInfo[] ctors = type.GetConstructors();
    // clone the property bag and make it case insensitive
    propertyBag = new Dictionary<string, object>(
        propertyBag, StringComparer.OrdinalIgnoreCase);
    ConstructorInfo bestCtor = null;
    ParameterInfo[] bestParams = null;
    for (int i = 0; i < ctors.Length; i++)
    {
        ParameterInfo[] ctorParams = ctors[i].GetParameters();
        if (bestCtor == null || ctorParams.Length > bestParams.Length)
        {
            bestCtor = ctors[i];
            bestParams = ctorParams;
        }
    }
    if (bestCtor == null) throw new InvalidOperationException(
         "Cannot create - no constructor");
    object[] args = new object[bestParams.Length];
    for (int i = 0; i < bestParams.Length; i++)
    {
        args[i] = propertyBag[bestParams[i].Name];
        propertyBag.Remove(bestParams[i].Name);
    }
    object obj = bestCtor.Invoke(args);
    // TODO: if we wanted, we could apply any unused keys in propertyBag
    // at this point via properties
    return obj;
}

Похожие вопросы