C # передает делегату список аргументов для конструктора класса в довольно сжатой форме - PullRequest
1 голос
/ 20 февраля 2012

В C # я могу передать делегату список аргументов для конструктора класса в довольно сжатой форме?

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

Func<MyClassConstructionArgsType, MyClass> make_MyClass =
    args => {return new MyClass(args);};

var n = make_MyClass(comma separated arguments);

Мне также нужно, чтобы не было копии описания аргументов, приведенное ниже, например, не является решением:

Func<int, string, MyClass> make_MyClass =
    (a, b) => {return new MyClass(a, b);};

Или по тем же причинам:

Class Args
{
    ...
}

Func<Args, MyClass> make_MyClass =
    a => {return new MyClass(a);};

var n = make_MyClass(Args(args));

Дито, где это так:

var n = make_MyClass<MyClass>(comma separated arguments);

Подход Object [] {разделенные запятыми} хорош, за исключением того, что необязательные параметры также должны поддерживаться.

Этот вопрос был создан в результате ответа Анастасиосиал на следующий вопрос: c # ссылка на класс в отличие от ссылки на экземпляр

Джош, первый ответ кажется настолько близким, насколько это возможно в C #.

Ответы [ 3 ]

2 голосов
/ 20 февраля 2012

Не без какой-либо формы отражения.

Вы можете создать делегата, который использует Activator:

Func<Object[], MyClass> makeClass =
   args => (MyClass) Activator.CreateInstance(typeof (MyClass), args);

makeClass(new object[] {"String", 32});

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

public static T BuildType<T>(params Object[] args) {
   return (T) Activator.CreateInstance(typeof (T), args);
}

BuildType<MyClass>("String", 32);

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

0 голосов
/ 20 февраля 2012

Как насчет чего-то по следующим строкам:

public delegate object VariableParamFactoryFunc(params object[] constructorParams);

public class Factory
{
    private Dictionary<Type, VariableParamFactoryFunc> _registeredTypes = new Dictionary<Type, VariableParamFactoryFunc>();

    public void RegisterType<T>(VariableParamFactoryFunc factoryFunc)
    {
        _registeredTypes.Add(typeof(T), factoryFunc);
    }

    public T Resolve<T>(params object resolutionParams)
    {
        VariableParamFactoryFunc factoryFunc;
        if (_registeredTypes.TryGetValue(typeof(T), out factoryFunc))
        {
            return (T)factoryFunc();
        }
        else
        {
            return default(T);
        }
    }
}

Тогда вы будете использовать это, сначала регистрируя фабричные функции: (например)

var factory = new Factory() // or you can turn it into a singleton, this is just for demonstration
factory.Register<IMyInterface>((a, b, c) => new ConcreteImplementation(a, b, c))
factory.Register<CustomClass>((a, b) => new CustomClass(a, b));

, а затем фактически решая и потребляяэти фабричные функции:

IMyInterface myInterface = factory.Resolve<IMyInterface>(1, "string", 2.412);
CustomClass customClass = factory.Resolve<CustomClass>("param1", 1234);

Это должно позволить вам гибко разрешать конструкторы с переменным числом параметров без потери производительности за Activator.CreateInstance или Reflection, но вы теряете в безопасности типов, так как все параметры будут приведенык объектам, и вам нужно будет привести их обратно к нужному типу в заводской функции

Удачи!

0 голосов
/ 20 февраля 2012

Я до сих пор не на 100% понимаю, что вы ищете здесь, но я попробую.

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

var makeX = new Func<String, Integer, X>((s,i)=>new X(s,i));

// To use it
var myX = makeX("Foo", 5);

Я не уверен, почему это не «приемлемо» в вашем случае использования. Если вы можете указать на конкретные технические или синтаксические проблемы с этим подходом, я постараюсь их решить.

EDIT:

Предполагая, что допустимо предопределить ваших собственных делегатов:

delegate X makeX(String s, Integer i);

тогда вы можете сделать:

var myMakeX = new makeX((s,i)=>new X(s,i));

// To use it
var myX = myMakeX("Foo", 5);

Но я подозреваю, что это как можно меньше. Теперь, если вы заранее знаете, что, например, все время хотите указать «Foo» в качестве значения для s, то вы можете создать другой делегат, который это замыкает (используя технику, называемую * 1017). * Выделка ):

var myCurryMaker = new Func<String, Func<Integer, X>>(s => return new Func<Integer, X>(i => new X(s, i)));
var myCurriedX = myCurryMaker("Foo");

// To use it
var myX = myCurriedX(5);
...