mardi 16 octobre 2018

Invoke method with generic expression and action as parameters

I need to call a method that looks like this:

public bool DoSomething<TEntity>(Expression<Func<TEntity, bool>> expression, Action<TEntity> action) where TEntity : class

However TEntity is only known at runtime.

I know how to Invoke the method like this:

Type classType = GetType();
MethodInfo mInfo = classType.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
MethodInfo genericMInfo = mInfo.MakeGenericMethod(GetMyType());
Object result = genericMInfo.Invoke(this, <WHAT GOES HERE>);

As you can see i don't know what to pass into the function. And thats the diffrence to This Question where a method without parameters is called.

Is there any way i can do this?

EDIT: Full Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Example
{
    public class Program
    {
        static void Main(string[] args)
        {
            var example = new Example();

            // Type know at compiletime:
            example.DoSomething<MyClass>((obj) => obj.Number > 2, (obj) => obj.Number = 500);

            // Type not know until runtime. Might be MyClass, MyOtherClass or MyNextClass
            Type classType = example.GetType();
            MethodInfo mInfo = classType.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
            MethodInfo genericMInfo = mInfo.MakeGenericMethod(GetMyType());

            var result = genericMInfo.Invoke(example, new object[] { /* Expression<Func<TEntity, bool>> and Action<TEntity> */ });
            // My problem now is how to create this Expression and Action even if i know TEntity only at runtime
        }

        static Type GetMyType()
        {
            // Imagine some user-input or any other dark magic here. For the example i`ll just return a type
            return typeof(MyOtherClass);
        }
    }

    public class Example
    {
        public bool DoSomething<TEntity>(Expression<Func<TEntity, bool>> expression, Action<TEntity> action) where TEntity : MyClass
        {
            // Real code does something more useful, but its the same principle
            var myList = new List<TEntity>(GetItems<TEntity>());

            if (myList.Count > 0)
            {
                var entry = myList.AsQueryable().Where(expression).FirstOrDefault();

                if (entry != null)
                {
                    action(entry);

                    return true;
                }
            }

            return false;
        }

        private IEnumerable<T> GetItems<T>()
        {
            // Real code does something diffrent
            for (int i = 0; i < 5; i++)
            {
                yield return (T)Activator.CreateInstance(typeof(T), i);
            }
        }
    }

    public class MyClass
    {
        public MyClass(int number)
        {
            Number = number;
        }

        public int Number { get; set; }
    }

    public class MyOtherClass : MyClass
    {
        public MyOtherClass(int number)
            : base(number++)
        {
        }
    }

    public class MyNextClass : MyClass
    {
        public MyNextClass(int number)
            : base(number--)
        {
        }
    }
}





Aucun commentaire:

Enregistrer un commentaire