Общие экземпляры делегатов - PullRequest
2 голосов
/ 12 марта 2010

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

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

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");
  }
}

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

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

Ответы [ 2 ]

7 голосов
/ 12 марта 2010

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

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

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 голосов
/ 17 октября 2013

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

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");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...