Динамический инициализатор типов C # - PullRequest
3 голосов
/ 19 февраля 2010

Я пытаюсь динамически создать что-то вроде инициализатора типа C #:

MyClass class = new MyClass { MyStringProperty= inputString };

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

Func<string,T> CreateFunc<T>();

И вызов результирующей функции создаст новый экземпляр 'T' с (например) каждым открытым свойством типа String со значением входной строкиАргумент.

Если предположить, что MyClass имеет только MyStringProperty, приведенный ниже код будет функционально эквивалентен коду в начале:

var func = CreateFunc<MyClass>();
func.Invoke(inputString);

Я довольно хорошо знаком с Системой.Пространства имен Reflection и System.Linq.Expressions, и в прошлом я делал такие сложные вещи, как эта, но эта поставила меня в тупик.Я хочу создать скомпилированный делегат, а не просто перебирать свойства, используя отражение.

Спасибо!

Ответы [ 3 ]

1 голос
/ 19 февраля 2010

Э-э, да, я просто слишком усложнял для себя. Это метод, который я искал:

public static Func<string, T> CreateFunc<T>()
    where T : class
{
    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
    var param = Expression.Parameter(typeof(string),"o");
    var constructorInfo = typeof(T).GetConstructor(new Type[] { });
    List<MemberBinding> bindings = new List<MemberBinding>();
    foreach (var property in properties)
        bindings.Add(Expression.Bind(property, param));

    var memberInit = Expression.MemberInit(Expression.New(constructorInfo), bindings);

    var func = Expression.Lambda<Func<string, T>>(memberInit, new ParameterExpression[] {param}).Compile();

    return func;            
}
1 голос
/ 19 февраля 2010

В CLR 4.0 вы сможете создавать полные операторы с помощью выражений.

До этого вы смотрите на задание по созданию кода.Самый быстрый способ создать прототип - создать C # в StringBuilder, а затем вызвать на нем компилятор.С кэшированием все будет в порядке.

Жесткий способ сделать это - сгенерировать IL и использовать Reflection Emit для построения метода, что позволит избежать вызова компилятора.

0 голосов
/ 19 февраля 2010

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

Как я вижу, вы можете сделать это только с помощью отражения. Не задумываясь, вам нужно знать во время компиляции каковы имена каждого свойства, которое вы хотите установить. Вы можете выполнять отдельные функции для каждого отдельного класса, который хотите поддерживать, но это противоречит требованию универсальной функции «один размер подходит всем».

Могу ли я спросить, почему функция в первую очередь? Некоторая форма внедрения зависимости?

...