C# 反射如何使用表达式 lambda 参数调用静态扩展方法

问题描述 投票:0回答:1

我定义了一个接口和一个类如下

    public interface IXmlKey
    {
        string Name { get; set; }
        string Value { get; set; }
        bool HasChildren { get; set; }
    }

    public interface IXmlKey<T> : IXmlKey where T : IXmlKey<T>
    {
        public T[] Children { get; set; }
    }

以及方法、代码

private static bool ReadSubXmlKeys(XmlReader subReader, IXmlKey objInstance, bool hasChildren,  out string error)
{
    error = null;

    var childrenProp = objInstance.GetType().GetProperties().Single(p => p.Name.Equals("Children"));
    var childType = childrenProp.PropertyType.GetElementType(); 
    var childPis = childType.GetProperties();

    var generateList = typeof(List<>).MakeGenericType(childType);

    var childrenList = Activator.CreateInstance(generateList); 
    var childrenListType = childrenList.GetType();

    //public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    var fun = typeof(Func<,>).MakeGenericType(childType, typeof(bool));

    var anyMethod = typeof(Enumerable).GetMethodWithLinq("Any", typeof(IEnumerable<>), typeof(Func<,>)).MakeGenericMethod(childType);
    
    var startNodeName = objInstance.Name;

    do
    {
        var nodeName = subReader.Name;
        //var isExist = anyMethod.Invoke(null, [childrenList, <what here>]); ---> here
 
    }
    while (subReader.Read());

    return true;
}

如您所见,我不确定调用 List.Any(t => t.Name.Equals(nodeName )) 的正确参数是什么,其中 T : IXmlKey

请帮忙。

c# lambda reflection expression
1个回答
0
投票

您需要传递

Func<childType,bool>
谓词。

拥有它的实例的一种方法是动态构建一个表达式并像这样编译它:

...
var anyMethod = typeof(Enumerable).GetMethodWithLinq("Any", typeof(IEnumerable<>), typeof(Func<,>)).MakeGenericMethod(childType);


...
var captureClass = new Capture { Name = "example" }; // mimic c# compiler to compile once

var parameterExpression = Expression.Parameter(childType, "t");
var propertyInfo = childType.GetProperty(nameof(IXmlKey.Name));
var propertyCall = Expression.Property(parameterExpression, propertyInfo);
var fieldAccess = Expression.Field(Expression.Constant(captureClass, typeof(Capture)), nameof(Capture.Name));
var equalsMethod = typeof(string).GetMethod("Equals", [typeof(string)]);
var expCall = Expression.Call(propertyCall, equalsMethod, fieldAccess);
var lambda = Expression.Lambda(expCall, [parameterExpression]);
var compiledPredicate = lambda.Compile();
...    

do
{
    captureClass.Name = subReader.Name;
    var isExist = anyMethod.Invoke(null, [childrenList, compiledPredicate]);

}
while (subReader.Read());

return true;

为了优化,你也需要这个类:

public class Capture {
    public string Name;
}
© www.soinside.com 2019 - 2024. All rights reserved.