Search code examples
c#lambdaexpression

How to build a lambda expression


I have lots of sub classes, inherited from IDbTypeHandler<T>, and I want know how to convert "SetValue" to lambda expression, after that I can call Action<IDbDataParameter, object>.

inteface

    public interface IDbTypeHandler
    {
    }
    public interface IDbTypeHandler<T> : IDbTypeHandler
    {
        void SetValue(IDbDataParameter parameter, T value);
    }

classes

    internal class UniqueidentifierUlIdHandler : IDbTypeHandler<UlId>
    {
        public void SetValue(IDbDataParameter parameter, UlId value)
        {
            parameter.Value = value.ToByteArray();
        }
    }
    internal class Char1Handler : IDbTypeHandler<bool>
    {
        public void SetValue(IDbDataParameter parameter, bool value)
        {
            parameter.Value = value;
        }
    }

---------------update------------------

the follow code is where i want to make a lambda expression

if (!TryGetValue("Key", out IDbTypeHandler dbTypeHandler))
{
   return false;
}

var t = dbTypeHandler.GetType();
var itf = t.GetInterfaces().SingleOrDefault(i => i.IsGenericType);
var xx = itf.GenericTypeArguments[0];

var p0 = Expression.Parameter(t);
var p1 = Expression.Parameter(typeof(IDbDataParameter));
var p2 = Expression.Parameter(xx);
var method = t.GetMethod("SetValue");
Type delegateType = typeof(Action<,,>).MakeGenericType(t, typeof(IDbDataParameter), xx);
var lambda = Expression.Lambda(delegateType, Expression.Call(p0, method, p1, p2), new[] { p0, p1, p2 });

now, i get a lambda. if i use .Compile(), then it will return a Delegate type. But, i want a Action<IDbDataParameter,object>

I know i need a type convert before var lambda = Expression.Lambda, but i don't know what to do for now.


Solution

  • I have recreated a little sample with 2 ways to implement lambda (see classes test1 and test2)

    internal class Program
    {
        static void Main(string[] args)
        {
            var one = new One();
            var two = new Two();
    
            var obj_int = new ClassX();
            var obj_str = new ClassX();
    
            var ActOne = new test1<int, One>();
            var ActTwo = new test1<string, Two>();
    
            ActOne.myLambda1(obj_int, 10, one);
            ActTwo.myLambda1(obj_str, "Youpi", two);
    
            Console.WriteLine($"one = {obj_int.Value} two = {string.Join(",",(char[])obj_str.Value)}");
    
            new test2<int, One>().myLambda2(obj_int, 20);
            new test2<string, Two>().myLambda2(obj_str, "Super");
    
            Console.WriteLine($"one = {obj_int.Value} two = {string.Join(",", (char[])obj_str.Value)}");
        }
    
    }
    //lambda with U instantiated
    public class test1<T,U> where U : ITest<T>
    {
        public Action<ClassX, T, U> myLambda1 = (arg1, arg2, arg3) =>
        {
            arg3.SetValue(arg1, arg2);
        };
    }
    //lambda with U not instantiated
    public class test2<T, U> where U : ITest<T> , new()
    { 
        public Action<ClassX, T> myLambda2 = (arg1, arg2) =>
        {
            new U().SetValue(arg1, arg2);
        };
    }
    
    public class ClassX
    {
        public object Value;
    }
    
    public interface ITest<T>
    {
        void SetValue(ClassX parameter, T value);
    }
    public class One : ITest<int>
    {
        public void SetValue(ClassX parameter, int value)
        {
            parameter.Value = value + 10;
        }
    }
    
    public class Two : ITest<string>
    {
        public void SetValue(ClassX parameter, string value)
        {
            parameter.Value = value.ToCharArray();
        }
    }
    

    result:

    one = 20 two = Y,o,u,p,i
    one = 30 two = S,u,p,e,r