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);
}
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,> {
}
}</tinterface>
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)
{
return Invoke<string, int>(p => p.GetLength, text);
}
}
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.