Сделать делегат для метода во время выполнения - PullRequest
0 голосов
/ 28 февраля 2020

Я нашел эту интересную статью Производительность отражения - создание делегата (свойства C#)

описанный подход отлично работает для свойств. Поэтому я попытался заставить его работать и для методов, но безуспешно.

Классы / Свойства / Методы

 public class bmecatContent
{
    private bmecatHeader header;
    private bmecatCatalog catalog;
    private List<bmecatFieldValue> fieldValueList;

    public bmecatContent()
    {
        header = new bmecatHeader();
        catalog = new bmecatCatalog();
    }

    public string DeclarationVersion { get; set; }
    public string DeclarationEncoding { get; set; }
    public string BmecatVersion { get; set; }

    public bmecatHeader Header
    { get { return header; } }
    public bmecatCatalog Catalog
    { get { return catalog; } }

}


public class bmecatCatalog
{
    private List<bmecatCatalogGroupSystem> catalogGroupSystem;
    private List<bmecatClassificationSystem> classificationSystem;
    private List<bmecatProduct> products;
    private List<bmecatProductToCataloggroupMap> productToCataloggroupMap;

    public bmecatCatalog()
    {
        catalogGroupSystem = new List<bmecatCatalogGroupSystem>();
        classificationSystem = new List<bmecatClassificationSystem>();
        products = new List<bmecatProduct>();
        productToCataloggroupMap = new List<bmecatProductToCataloggroupMap>();
    }

    public List<bmecatClassificationSystem> Classification_System
    { get { return classificationSystem; } }
    public List<bmecatCatalogGroupSystem> Catalog_Group_System
    { get { return catalogGroupSystem; } }
    public List<bmecatProduct> Products
    { get { return products; } }
    public List<bmecatProductToCataloggroupMap> Product_To_Cataloggroup_Map
    { get { return productToCataloggroupMap; } }

    public bmecatProduct GetProductByInernationalPid(string Pid)
    {
        // linq
        var query = from prodItem in products
                   from innerList in prodItem.Product_Details.International_PID
                   where innerList.PID == Pid
                   select prodItem;
        return query.FirstOrDefault();

    }
}

Мой текущий подход выглядит так:

// Properties
public static Func<object, object> BuildGetAccessor(MethodInfo method)
    {
        var obj = Expression.Parameter(typeof(object), "o");

        Expression<Func<object, object>> expr =
            Expression.Lambda<Func<object, object>>(
                Expression.Convert(
                    Expression.Call(
                        Expression.Convert(obj, method.DeclaringType),
                        method),
                    typeof(object)),
                obj);

        return expr.Compile();

    }

// Methods (with string Parameter)
public static Func<object, string, object> BuildMethodAccessor(MethodInfo method)
    {
        var obj = Expression.Parameter(typeof(object), "o");
        var strParam = Expression.Parameter(typeof(string), "strParam");
        //var param = method.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).FirstOrDefault();
        var param = Expression.Convert(strParam, method.GetParameters().First().ParameterType);

        Expression<Func<object, string, object>> expr =
            Expression.Lambda<Func<object, string, object>>(
                Expression.Convert(Expression.Call(Expression.Convert(obj, method.DeclaringType), method, param),
                    typeof(object)),
                obj);

        return expr.Compile();

    }

этот код генерирует сообщения о том, что для лямбда-объявления использовалось неверное количество параметров. Спасибо большое за вашу помощь!

// Обновите это моя часть "в процессе", когда речь идет о создании и использовании делегатов:

bmecatParser parser = new bmecatParser();
// parser contains Property BmecatContent of type bmecatContent
// BmecatContent contains all properties and Methods I Need to Access at runtime
// e.g. BmecatContent.Catalog, BmecatContent.Catalog.GetProductByInernationalPid(string Pid)


// gets instance of main-class
var property = parser.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(obj => obj.Name == "BmecatContent");
var access = Extensions.BuildGetAccessor(property.GetGetMethod());
var resultBmecatContent = access(parser);

// gets instance of class that holds method
property = resultBmecatContent.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(obj => obj.Name == "Catalog");
access = Extensions.BuildGetAccessor(property.GetGetMethod());
var resultCatalog = access(resultBmecatContent);

// here I try to get value from method that has 1 Parameter (string)
var method = resultCatalog.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Single(obj => obj.Name == "GetProductByInernationalPid");
var accessProd = Extensions.BuildMethodAccessor(method);
var resultProduct = accessProd(resultCatalog, "4317784548366");

Идея заключается в том, чтобы анализировать заданные классы + структуру свойств, где пользователь предоставляет имена свойств / методов в инструкциях отображения.

...