Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C#3.0 C# C#4.0
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) (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
}
 
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>
 
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...
}
 
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.
Posted 17-May-11 11:33am
Edited 18-May-11 1:13am
v4

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

Just Check My Implementation
 
public interface ITest
   {
       int GetLength(string text);
       // many other methods...
   }
 
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 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
   }
 
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.
  Permalink  
Comments
glFrustum at 18-May-11 5:44am
   
Thanks for your suggestion, but I think you assume that all methods of ITest return int. If the methods of ITest have n different types for TResult, you would need n different Invoke methods. I updated the code of ITest to point that out.
 
The goal was to use just one Invoke method for all Func<TArg, TResult> without explicit type arguments like Invoke(p => p.GetLength, text).
nissims at 31-Aug-13 5:36am
   
Hi
I'm sorry but i don't understand what you are trying to do.
can you send me a reproduce code (just copy your code to a console app including the part that don't work)
I have deal with that kind of problems in the past i want to be sure that this is the case in order to give you the correct answer (if this is the situation)
Abhishek Sur at 18-May-11 13:58pm
   
That is very simple, use T as Return type argument rather than explicit int. Also remember, if you are to specify any type as Func return type in Invoke other than Targs and TResult, you need to specify it here as well.
glFrustum at 18-May-11 19:14pm
   
Its only simple if you pass the parameter twice :-) I would be very happy to get rid of (request) behind c.GetFoo, but can't find the solution.
 
public FooDto GetFoo(GetFooRequest request) {
return Invoke(c => c.GetFoo(request), request);
}
 
In order to avoid the duplicate parameter, the type arguments must be specified, but this isn't very elegant, too.
 
public FooDto GetFoo(GetFooRequest request) {
return Invoke<FooDto, GetFooRequest>(c => c.GetFoo, request);
}
 
It looks like I would have to decide between these two variants...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Advertise | Privacy | Mobile
Web04 | 2.8.141220.1 | Last Updated 18 May 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100