Общие экземпляры делегатов

2

Интересно, поддерживает ли С# (или базовую платформу .NET) какие-то "общие экземпляры делегатов": это экземпляр делегата, который все еще имеет неразрешенный параметр типа, который должен быть разрешен во время вызова делегата (не на момент создания делегата). Я подозреваю, что это невозможно, но я все равно прошу...

Вот пример того, что я хотел бы сделать, с некоторыми "???" вставлен в места, где синтаксис С# кажется недоступным для того, что я хочу. (Очевидно, этот код не компилируется)

class Foo {
  public T Factory<T>(string name) {
    // implementation omitted
  }
}

class Test {
  public void TestMethod()
  {
    Foo foo = new Foo();
    ??? magic = foo.Factory; // No type argument given here yet to Factory!
                             // What would the '???' be here (other than 'var' :) )?
    string aString = magic<string>("name 1"); // type provided on call
    int anInt = magic<int>("name 2"); // another type provided on another call

    // Note the underlying calls work perfectly fine, these work, but i'd like to expose
    // the generic method as a delegate.
    string aString2 = foo.Factory<string>("name 1");
    int anInt2 = foo.Factory<int>("name 2");
  }
}

Есть ли способ сделать что-то подобное на С#? Если это не так, это ограничение в языке или оно есть в платформе .NET?

Изменить: Причина, по которой я спрашиваю, заключается в том, что я хотел бы передать делегат функции в другую сборку и не хочу требовать, чтобы другая сборка ссылалась на какой-либо конкретный тип (класс "Foo" в моем примере). Я надеялся согнуть стандартный делегат Func < > таким образом, чтобы он соответствовал "???" часть.

  • 0
    C # также знает слово var, и оно будет напечатано при сборке.
  • 0
    Вы знаете, что можете foo.Factory <string> ("name 1"), я полагаю. Не могли бы вы расширить свой вопрос, чтобы объяснить, почему вам нужно использовать магию <string>, а не foo.Factory <string>?
Показать ещё 4 комментария
Теги:
generics
delegates

2 ответа

7
Лучший ответ

Это невозможно, так как то, что вы просите, объявляет переменную (magic) типа закрытых дженериков.

Можно работать с незакрытыми генериками, но только на уровне типа, например:

delegate T FactoryDelegate<T>(string name);

var magicType = typeof (FactoryDelegate<>);

и затем "закрыть" тип в более поздней точке:

var stringMagic = magicType.MakeGenericType(typeof(string));

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

    public class UnclosedMethod
    {
        private readonly MethodInfo _method;

        public UnclosedMethod(Type type, string method)
        {
            _method = type.GetMethod(method);
        }

        public T Invoke<T>(string name)
        {
            var fact = _method.MakeGenericMethod(typeof(T));
            return (T)fact.Invoke(this, new object[] { name });
        }
    }

И затем в коде выполните следующее:

var magic = new UnclosedMethod(typeof(Foo), "Factory");
var x = magic.Invoke<string>("bar");
  • 0
    спасибо за ответ, я уже подозревал что-то подобное. Это оставляет открытой вторую часть вопроса: «Это ограничение в языке C # или в .NET Framework».
0

Просто что-то вроде?:

Foo foo = new Foo();
string aString = 
   foo.GetType().GetMethod("Factory").MakeGenericMethod(string)
       .Invoke(foo, new object[] { "name 1" });
int anInt = 
   foo.GetType().GetMethod("Factory").MakeGenericMethod(int)
       .Invoke(foo, new object[] { "name 2" });

Теперь, если вы хотите использовать делегат, вы можете получить что-то вроде:

public delegate T FactoryDelegate<T>(string name);

Затем вы можете сделать вызов, например:

public TestMethod1(FactoryDelegate<dynamic> factory)
{
    object o = factory("name 3");
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню