oronsultan Ответов: 2

Изменить значение анонимного свойства типа string


Привет,
Я работаю над приложением, написанным на WPF, код написан на C#.
У меня есть значок вопросительного знака, который при нажатии предполагает установку содержимого на определенную метку.
Содержимое метки привязывается к свойству в модели представления, давайте назовем его "NoneLegend".
Я хочу, чтобы это свойство очистилось через 5 секунд, поэтому у меня есть служебный класс, который должен управлять этим. Внутри этого класса я написал анонимный метод, который получает любой тип свойства.
Мой вопрос заключается в том, как мне установить это свойство в string.empty?
Метод выглядит следующим образом:
public static void EmptyStringAfterXseconds<T>(Expression<Func<T>> property)
        {
            var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
            if (propertyInfo == null)
            {
                throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
            }
            else
            {
                var t = propertyInfo.GetType();
                propertyInfo.SetValue(null, "");
            }
        }

И я называю это именно так:
NoneLegend = "Bla bla...";
Utils.EmptyStringAfterXseconds(() => NoneLegend);


Что я уже пробовал:

..................................................................

2 Ответов

Рейтинг:
6

Richard Deeming

Если вы можете изменить вызывающий код, то было бы проще передать Action<T> чтобы обновить значение свойства.

В противном случае вам нужно будет извлечь целевой экземпляр из выражения. Но имейте в виду, это довольно хрупко.

public static class ExpressionExtensions
{
    private static object GetSourceObject(MemberExpression body)
    {
        if (body.Expression is ConstantExpression c)
        {
            return c.Value;
        }
        
        if (body.Expression is MemberExpression m && m.Expression is ConstantExpression mc)
        {
            if (m.Member is FieldInfo f) return f.GetValue(mc.Value);
            if (m.Member is PropertyInfo p) return p.GetValue(mc.Value);
        }
        
        throw new NotSupportedException("Invalid expression: " + body);
    }
    
    public static (object instance, PropertyInfo property) ExtractProperty(LambdaExpression expression)
    {
        if (expression is null) throw new ArgumentNullException(nameof(expression));
        
        if (expression.Body is MemberExpression body && body.Member is PropertyInfo property)
        {
            object instance = GetSourceObject(body);
            return (instance, property);
        }
        
        throw new NotSupportedException("Invalid expression: " + expression);
    }
}
public static void SetPropertyAfterXseconds<T>(Expression<Func<T>> propertyToSet, T valueToSet = default)
{
    var (instance, property) = ExpressionExtensions.ExtractProperty(propertyToSet);
    property.SetValue(instance, valueToSet);
}
Это позволит поддерживать два типа вызовов:
public class Foo
{
    public string Bar { get; set; }
    
    public void DoIt()
    {
        // Option 1:
        SomeClass.SetPropertyAfterXseconds(() => Bar);
    }
}

// Option 2:
Foo x = new Foo { Bar = "Baz" };
SomeClass.SetPropertyAfterXseconds(() => x.Bar);
Для варианта 1 выражение тела будет иметь вид ConstantExpression указывая на this.

Для варианта 2 выражение тела будет иметь вид MemberExpression указание на поле в классе замыкания, сгенерированном компилятором.


oronsultan

Привет, Ричард, Извини за поздний ответ.
Большое вам спасибо за то, что вы приложили столько усилий, чтобы написать подробный ответ. Это прекрасно работает!

Рейтинг:
0

Gerry Schmitz

Вам нужен "объект", чтобы идти вместе с информацией о вашей собственности.

"Информация" - это метаданные; объект (то есть "метка") - это ссылка для получения / настройки свойств. "нуль" этого не сделает.

Метод PropertyInfo.SetValue (System.Размышления) | Майкрософт Документы[^]