0

I found this interesting article Reflection Performance - Create Delegate (Properties C#)

the described approach works great for properties. So I tried to to make it work for Methods, too, but without success.

Classes / Properties / Methods

 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();

    }
}

my current Approach looks like:

// 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();

    }

this code generates messages, that for the lambda-declaration a wrong number of Parameters was used. thx a lot for your help!

// Update this is my "work in progress" part when it Comes to creating & using the delegates:

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");

the idea behind this is to parse given classes + properties structure, where user provides propertynames / methodnames within mappinginstructions.

jake
  • 23
  • 3
  • 2
    Why should your delegate expect an `object` and a `string`, whereas `GetPersonByName` expecty only a `string`? Could you please add for which method you want to create the delegate? How would you call `BuildMethodAccessor`? I assume something like `Func<...> del = BuildAccessorMethod(typeof(Process).GetMethod("GetPersonByName"))`, correct? – MakePeaceGreatAgain Feb 28 '20 at 14:39
  • @HimBromBeere pls have a look at the update I made. Hope it becomes clearer what I try to achieve – jake Feb 28 '20 at 16:37
  • 1
    In your update it seems you omitted some code. Can you please provide that for the full context? Or, can you provide a method you'd like to convert into an expression tree? I have a lot of experience with this and probably can help you, I just need some more information. – Jedi_Maseter_Sam Feb 28 '20 at 18:20
  • 1
    In particular it´ll be helpfull if you´d provided the type of `resultBmecatContent` and the method you want to get a delegate for. – MakePeaceGreatAgain Feb 28 '20 at 21:09
  • 1
    Anyway I have the strong feeling yore overcomplicating things. Why do you even built expression-trees here? All you get is an `object`, so I can´t see much benefit over pure reflection or even better direct member-access. However we don´t have the greater image why you think you need this. – MakePeaceGreatAgain Feb 28 '20 at 21:11
  • @HimBromBeere thx for your feedbacks! I updated my question. the whole bmecatContent class cotains lots of classes, each with lots of properties and Methods I Need to Access at run by Name. Methods will return different types, but have 1 Parameter of type string. e.g. the returnvalue of method "GetProductByInernationalPid" is a an instance of a class and will be used to Access further properties / Methods. I chose this approach mainly because it's something new for me. – jake Feb 29 '20 at 06:57

0 Answers0