使用Generics指定lambda表达式但具有模板化类型

时间:2014-01-27 21:16:44

标签: c# generics lambda substitution

我有一个有趣的问题。

public Func<T, int> GetLambdaFor<T>()
{
   // ....
}

public void SetLambdaForAnyType(Func<?, int> lambda)
{
   // ....
}

在上面的代码示例中,我想知道在检索特定类型的{时,是否可以使用SET方法在Generic中指定可替换的lambda expression C#。 {1}} Generic使用GET方法。

那么,让我举一个例子(当然它的特点是破碎lambda expression,我想知道是否有可能,如果可行,怎么做):

C#

我希望现在更有意义。有任何想法吗?如果不可能,还有其他可能性吗?

2 个答案:

答案 0 :(得分:4)

lambda表达式不能引入泛型参数,没有语法。您将不得不使用泛型方法而不是lambdas,并使用反射为特定类型构造封闭的泛型方法,如下所示(代码未测试):

public Func<T, int> GetLambdaFor<T> ()
{
    return GetLambdaFor<T> (m_method, m_target) ;
}

public void SetLambdaForAnyType (Func<object, int> lambda)
{
   if (lambda == null) throw new ArgumentNullException ("lambda") ;

   // delegate complicated signature checks to CLR
   try
   {
       var definition = lambda.Method.GetGenericMethodDefinition () ;
       GetLambdaFor<Dummy> (definition, lambda.Target) ;
       m_method = definition ;
       m_target = lambda.Target ;
   }
   catch (Exception e)
   {
       throw new ArgumentException ("lambda", e) ;
   }
}

private sealed class Dummy {}
private MethodInfo m_method ;
private object     m_target ;
static Func<T, int> GetLambdaFor<T> (MethodInfo method, object target)
{
    return (Func<T, int>) Delegate.CreateDelegate (typeof (Func<T, int>),
        target, method.MakeGenericMethod (typeof (T))) ;
}

然后你就像这样使用它

// in your class
private static int GetValueFromGenerator<T> (T a)
{
    return new SomeValueGenerator<T> (a).GetValue () ;
}

MyClass.SetLambdaForAnyType (GetValueFromGenerator) ;

最后,如果你的'lambdas'将始终是这种形式,你可能想要为GetValue引入一个接口而不是动态创建通用方法,为这些生成器创建泛型类型,激活他们并投向IGetValue

答案 1 :(得分:3)

你可以做到,当然。你在这种类型中失去了类型安全性,但我们知道从外部角度看它也能正常工作:

public class Foo
{
    private Dictionary<Type, Delegate> dictionary =
        new Dictionary<Type, Delegate>();

    public Func<T, int> GetLambdaFor<T>()
    {
        return dictionary[typeof(T)] as Func<T, int>;
    }
    public void SetLambdaFor<T>(Func<T, int> func)
    {
        dictionary[typeof(T)] = func;
    }
}

当然,如果您想处理该类型没有条目的情况,您可能希望使用字典中的TryGetValue

另一种选择是使用线程静态字段:

public class Foo2<T>
{
    [ThreadStatic]
    public Func<T, int> Generator { get; set; }
}

然后它就像:

一样简单
Foo2<string>.Generator = s => 5;
int result = Foo2<string>.Generator("asdf");