Lambda表达式的隐式类型参数推导 [英] Implicit type argument deduction with lambda expressions

查看:270
本文介绍了Lambda表达式的隐式类型参数推导的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我正在寻找一种优雅的方法来从包装器调用某个接口的方法,以便包装器(或其基类)可以访问方法签名和参数值.应该使用Lambda表达式来支持智能感知(例如interface => interface.DoSomething).

这样,包装器(TestWrapper)保持尽可能简单,并且所有方法的任何其他功能都可以在包装器(WrapperBase<tinterface></tinterface>)的基类中的单个点实现(例如,缓存,日志记录,参数处理)或结果等).

界面
此接口由类TestWrapper实现和包装.想象一下,还有一些其他接口必须与相同的通用基类WrapperBase<TInterface>一起使用,并且不需要特殊的基类.

Hi everybody,

I''m looking for a an elegant way to invoke methods of a certain interface from a wrapper, so that the wrapper (or its base class) has access to the method signature and the value of the argument. Lambda expressions should be used in order to support intellisense (like interface => interface.DoSomething).

This way the wrapper (TestWrapper) is kept as simple as possible and any additional functionality for all methods can be implemented at a single point in the base class of the wrapper (WrapperBase<tinterface></tinterface>) (e.g. caching, logging, processing of arguments or results etc).

Interface
This interface is implemented and wrapped by the class TestWrapper. Imagine that there are some other interfaces that have to work with the same generic base class WrapperBase<TInterface> and should not require special base classes.

public interface ITest
{
    int GetLength(string text);
    FooResponse GetFoo(GetFooRequest r);
    BarResponse GetBar(GetBarRequest r);
    // lots of other method signatures
}



包装器基类
要求委托Method传递不带参数的方法. TInterface的实现由继承类TestWrapper注入.



Wrapper base class
The delegate Method is required to pass a method without its arguments. The implementation of TInterface is injected by the inheriting class TestWrapper.

public delegate TResult Method<TArg, TResult>(TArg arg);

public class WrapperBase<tinterface> where TInterface : class
{
    private TInterface _value;

    // ...

    protected TResult Invoke<targ,>(
        Func<TInterface, Method<targ,>    {
        // method and argument are required for
        //  execution, caching, logging, other processing...
    }
}</tinterface>



包装器实现
此类实现ITest并将其所有方法调用都委派给其基类,在该类中,所有方法的附加功能都在单个点上实现,而不是在TestWrapper的每个方法上实现.
此类可以像var testWrapper = new TestWrapper(new TestImplementation())
一样使用



Wrapper implementation
This class implements ITest and just delegates all method calls to its base class, where additional functionality for all methods is implemented at a single point instead of every method of TestWrapper.
This class can be used like var testWrapper = new TestWrapper(new TestImplementation())

public class TestWrapper : WrapperBase<ITest>, ITest
{
    public TestWrapper(ITest value) : base(value) { }
    public int GetLength(string text)
    {
        // type arguments cannot be derived
        // return Invoke(p => p.GetLength, text);

        // works fine
        return Invoke<string, int>(p => p.GetLength, text);
    }
    // many other methods...
}



问题
如上面的代码片段所示,编译器仅接受第二条语句(带有类型的参数).上一行引发错误,因为无法派生类型参数.

1)我使用的第一个WrapperBase解决方案
TResult Invoke<TResult>(Func<TInterface, TResult> command)
可以由TestWrapperbase.Invoke(t => t.GetLength(text))调用,而没有任何类型参数.
唯一的缺点是Invoke方法无法访问参数值(此处为text),因此该参数不能用于缓存,验证等.

2)我使用的第二个解决方案
public TResult Invoke<TResult>(Expression<Func<TInterface, TResult>> command).
可以使用与第一个解决方案相同的方式(没有任何类型参数)来调用它,并允许访问该参数.该解决方案的缺点是表达式必须先编译才能执行.我真的不想对每个方法调用都使用Compilation and Reflection.

问题
Invoke方法的签名可以更改,以便正确推导类型参数吗?

欢迎任何想法!
谢谢

更新
1)编辑器弄乱了Invoke方法的声明;这是固定的.
2)在ITest中添加了其他方法,以表明所有结果和参数类型都是不同的.



Problem
As shown in the above code snippet only the second statement is accepted by the compiler (with type arguments). The line above throws an error, because the type arguments can not be derived.

1) My first solution of WrapperBase used
TResult Invoke<TResult>(Func<TInterface, TResult> command)
and could be called by TestWrapper with base.Invoke(t => t.GetLength(text)) without any type arguments.
The only disadvantage was that the Invoke method had no access to the argument value (here text), so the argument could not be used for caching, validation etc.

2) My second solution used
public TResult Invoke<TResult>(Expression<Func<TInterface, TResult>> command).
It could be called the same way as the first solution (without any type arguments) and allowed access to the parameter. The disadvantage of this solution is that the expression has to be compiled before it can be executed. I really don''t want to use Compilation and Reflection for every single method call.

Question
Can the signature of the Invoke method be changed, so that the type arguments can be deducted correctly?

Any ideas are welcome!
Thanks

Update
1) The editor messed up the declaration of the Invoke method; this was fixed.
2) Other methods were added to ITest to show that all result and argument types are different.

推荐答案

只需检查我的实现

Just Check My Implementation

public interface ITest
   {
       int GetLength(string text);
       // many other methods...
   }



该接口具有GetLength方法.





The interface has GetLength method.



public class TestClass<TInterface> where TInterface : ITest
{
    protected TResult Invoke<TArg, TResult>(Func<TInterface, int> method, TArg arg)
    {

        return default(TResult);
    }
}



创建对象时,TestClass接受ITest的输入并将其存储为Type参数.从调用方法,我正在使用此界面.我们有意将Func返回类型设置为int,因为我们稍后将调用getLength.





TestClass takes an input of ITest and stores it as Type argument when object is created. From Invoke Method I am using this interface. We intentionally made Func returntype as int as we are going to call getLength later.



public class WrapperITest : ITest
 {

     #region ITest Members

     public int GetLength(string text)
     {
         return text.Length;
     }

     #endregion
 }



ITest的实现,它将定义GetLength方法.您将返回类型指定为int,因此它对Type参数具有严格的规则



Implementation of ITest which will have GetLength method defined. You specified return type as int, so it has strict rule on Type argument

public class TestWrapper : TestClass<ITest>
 {
     public int GetLength(string text)
     {
         return Invoke<string, int>(p =>  p.GetLength(text), text);
     }
 }



希望对您有所帮助.



I hope this will help.


这篇关于Lambda表达式的隐式类型参数推导的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆