Интересно, поддерживает ли С# (или базовую платформу .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 < > таким образом, чтобы он соответствовал "???" часть.
Это невозможно, так как то, что вы просите, объявляет переменную (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");
Просто что-то вроде?:
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");
}