конструктор как делегат - действительно ли это возможно в C#?

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

Скажем, у нас есть:

<div>
  <ul>
    <li><a>Pants</a></li>
    <li><a>Socks</a></li>
    <ul>
      <li><a>White socks</a></li>
      <li><a>Blue socks</a></li>
    </ul>
  </ul>
</div>

Что мы можем сделать, чтобы блок Socks (включая цвета носка) выделялся визуально с использованием интервала?

Что было бы неплохо, но не существует:

ul li ul:parent {
  margin-top: 15px;
  margin-bottom: 15px;
}

Что существует:

li > a {
  margin-top: 15px;
  display: block;
}
li > a:only-child {
  margin-top: 0px;
}

Это устанавливает, что все привязные ссылки имеют верхний край 15px и сбрасывают его обратно на 0 для тех, у которых нет элементов UL (или других тегов) внутри LI.

57
задан akavel 21 October 2009 в 03:47
поделиться

7 ответов

Нет, CLR не позволяет привязывать делегатов к ConstructorInfo .

Однако вы можете просто создать свой собственный:

static T Make<T>(Action<T> init) where T : new()
{
  var t = new T();
  init(t);
  return t;
}

Использование

var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });
29
ответ дан 7 November 2019 в 06:04
поделиться

Другая опция состояла бы в том, чтобы использовать Activator класс, как так:

Используя Универсальные Типы

public delegate Foo FooGeneratorDelegate<T>(int x);

public T FooGeneratorFunction<T>(int x)
{
    return (T)Activator.CreateInstance(typeof(T), x);
}

// implementation example
FooGeneratorDelegate<Foo> del = FooGeneratorFunction<Foo>;
Foo foo = del(someIntValue);

Передача Вашего Нечто Типа в качестве параметра

public delegate object FooGeneratorDelegate(Type t, int x);

public object FooGeneratorFunction(Type t, int x)
{
    return Activator.CreateInstance(t, x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = (Foo)del(typeof(Foo), someIntValue);

, Если Тип будет Всегда иметь Тип Foo

public delegate Foo FooGeneratorDelegate(int x);

public Foo FooGeneratorFunction(int x)
{
    return (Foo)Activator.CreateInstance(typeof(Foo), x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = del(someIntValue);
0
ответ дан 7 November 2019 в 06:04
поделиться

Я думаю, что настолько кратким, насколько вы собираетесь получить (без перехода к заводскому шаблону), было бы что-то с анонимными методами, например:

delegate Foo FooGenerator(int x);

...    

void DoStuff()
{
    YourDelegateConsumer(x => new Foo(x));
}

Это не делает строго то, что вы запрашивается (поскольку вы передаете делегата анонимному методу, который возвращает новый экземпляр, а не прямому делегату конструктору), но я не думаю, что то, что вы просите, строго возможно.

Это конечно при условии, что вы используете 3.5+

7
ответ дан 7 November 2019 в 06:04
поделиться

Похоже, вы, вероятно, захотите использовать шаблон фабрики классов.

Шаблон фабричного метода

5
ответ дан 7 November 2019 в 06:04
поделиться

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

2
ответ дан 7 November 2019 в 06:04
поделиться

Я предполагаю, что это не Это возможно, так как вы должны передать метод объекта, который еще не был создан.

0
ответ дан 7 November 2019 в 06:04
поделиться

Я предполагаю, что вы обычно делаете что-то подобное в рамках реализации фабрики, где фактические типы не известны во время компиляции ...

Во-первых, обратите внимание, что более простым подходом может быть этап инициализации после создания, тогда вы можете использовать универсальные шаблоны:

static T Create<T>({args}) where T : class, ISomeInitInterface, new() {
    T t = new T();
    t.Init(args);
    return t;
}

Затем вы можете использовать MakeGenericMethod и / или CreateDelegate .


В противном случае; вы можете сделать это «на лету» с помощью Expression (3.5) или DynamicMethod (2.0).

Подход Expression проще закодировать:

    var param = Expression.Parameter(typeof(int), "val");
    var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    var lambda = Expression.Lambda<Func<int, Foo>>(
        Expression.New(ctor, param), param);
    var func = lambda.Compile();
    Foo foo = func(123);
    string s = foo.ToString(); // proof

или (используя DynamicMethod ):

    ConstructorInfo ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    DynamicMethod dm = new DynamicMethod("Create", typeof(Foo),
            new Type[] { typeof(int) }, typeof(Foo), true);
    ILGenerator il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, ctor);
    il.Emit(OpCodes.Ret);
    Converter<int, Foo> func = (Converter<int, Foo>)
        dm.CreateDelegate(typeof(Converter<int, Foo>));        
    Foo foo = func(123);
    string s = foo.ToString(); // proof
55
ответ дан 7 November 2019 в 06:04
поделиться
Другие вопросы по тегам:

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