Размышления C# о том, как вызвать метод статических расширений с параметром выражения лямбда

Я определил интерфейс и класс следующим образом:

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<T>.Any(t => t.Name.Equals(nodeName )) where T : IXmlKey
Activator.CreateInstance(generateList) образует пустой список. Почему вы пытаетесь вызвать Any из пустого списка? Или это просто демонстрационный код, иллюстрирующий проблему, а в вашем реальном коде что-то другое?
Sweeper 03.08.2024 16:11

не демо-код. в цикле do { ... } while() я проверю, существует ли имя узла уже или нет. если существует, выдать исключение. в противном случае добавьте в список

goldii 03.08.2024 16:18

Мне непонятно, зачем вам рефлексия. Почему вы не можете запросить XML-данные напрямую? Пожалуйста, объясните, чего вы пытаетесь достичь.

Olivier Jacot-Descombes 03.08.2024 16:32

@OlivierJacot-Decombes, моя проблема в том, что я не знаком с параметром отражения вызова общего статического метода, который представляет собой лямбда-выражение. Что касается чтения XML, то это просто бизнес-сцена.

goldii 03.08.2024 16:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно передать предикат Func<childType,bool>.

Один из способов получить его экземпляр — динамически создать выражение и скомпилировать его следующим образом:

...
var captureClass = new Capture();
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;
}

полный пример на dotnetfiddle

Однако, на мой взгляд, есть лучшая альтернатива: просто создать общий метод для пересылки с вашей исходной Any логикой:

private static bool ReadSubXmlKeys<T>(XmlReader subReader, T objInstance, bool hasChildren, out string error) 
where T:IXmlKey<T>{
    var name = "example";
    var result = objInstance.Children.Any(t => t.Name.Equals(name));
}

Вам все еще нужно немного подумать, чтобы вызвать его в начале исходного необщего метода:

var genericDefinition = objInstance.GetType().GetInterfaces()
        .Where(x => x.IsGenericType)
        .Where(x => x.GetGenericTypeDefinition() == typeof(IXmlKey<>));

if (genericDefinition.Count() == 1) {

    // you can cache this in a static field too
    var genericMethodInfo = typeof(YourTypeThatHasTheStaticMethods)
        .GetMethod(nameof(ReadSubXmlKeysGeneric), BindingFlags.NonPublic | BindingFlags.Static);

    var genericMethod = genericMethodInfo.MakeGenericMethod(
        genericDefinition.First().GetGenericArguments()[0]);

    return (bool)genericMethod.Invoke(null, [subReader, objInstance...]);
}
... no need for the first solution
... since it relied on the Children property which is only
... there for IXmlKey<T>

ну, большое спасибо. это полезно

goldii 04.08.2024 01:38

Поскольку делегаты контравариантны по типам параметров, вы можете просто передать Func<IXmlKey, bool>, который можно написать напрямую. Это совместимо с Func<childType, bool>.

Sweeper 04.08.2024 02:00

@Подметальная машина. я делал тесты. один: частный статический bool IsSame(IXmlKey objInstance) { ... }, второй: Func<IXmlKey, bool> f = item => { .... } . оба они не огонь.

goldii 04.08.2024 09:56

@goldii Является ли childType типом значения? Это действительно не сработает. Что вы имеете в виду под «не огонь»? Это вызвало исключение?

Sweeper 04.08.2024 10:03

@Sweeper, 1. childType — это ссылочный тип. 2. отладить и запустить AnyMethod.Invoke(null, [childrenList, <что здесь>]); , вы увидите IsSame(IXmlKey objInstance) { ... }, Func<IXmlKey, bool> f = item => { .... } не войдет в

goldii 06.08.2024 06:29

Другие вопросы по теме