Как я могу использовать динамик c, чтобы узнать, когда используется свойство? - PullRequest
0 голосов
/ 26 мая 2020

Я хотел бы узнать, какое из свойств исходного объекта ввода использовал метод. После выполнения метода мне нужно сохранить в базе данных, какое из свойств было использовано.

Входными данными может быть любой класс с простыми типами, например:

public class MyData : IMyData
{
    public string A { get; set; }
    public int B { get; set; }
    public decimal C { get; set; }
}

Я думал, что может быть выполнено с использованием интерфейса в качестве входных данных для метода, поэтому я могу заменить исходный объект более продвинутым объектом, который хранит использование свойств.

public interface IMyData
{
    string A { get; }
    int B { get; }
    decimal C { get; }
}

Я могу затем

  1. Создайте объект Dynami c с такими же свойствами
  2. Используйте ImpromptuInterface, чтобы имитировать динамический c объект, реализующий мой интерфейс
  3. Вызвать мой метод с этим динамическим c интерфейсом

    private static void Main()
    {
        var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
    
        IDictionary<string, object> replacementObject = new ExpandoObject();
        replacementObject.Add("FieldsUsed", new List<string>());
        foreach (var property in data.GetType().GetProperties())
            replacementObject.Add(property.Name, property.GetValue(data));
    
        var replacementInterface = replacementObject.ActLike<IMyData>();
    
        DoStuff(replacementInterface);
        Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)replacementObject["FieldsUsed"])}");
    }
    
    private static void DoStuff(IMyData source)
    {
        Console.WriteLine($"A is {source.A}");
        if (source.B > 5)
            Console.WriteLine($"C is {source.C}");
    }
    

В приведенном выше примере я хотел бы сохранить, что использовались поля A и B.

Только я застрял в том, как я должен хранить, когда свойство используется моим методом DoStuff.

Ответы [ 2 ]

0 голосов
/ 26 мая 2020

Вы можете написать такую ​​обертку:

public class ClassWrapper<T>: DynamicObject where T:class
{
    private readonly T _obj;
    private readonly List<string> _fieldsUsed=new List<string>();
    public ClassWrapper(T obj)
    {
        _obj = obj;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        PropertyInfo propertyInfo = _obj.GetType().GetProperty(binder.Name);
        _fieldsUsed.Add(binder.Name);
        result = propertyInfo.GetValue(_obj);
        return true;
    }
    public List<string> GetFieldsUsed() => _fieldsUsed;

    public T GetWrapper()
    {
        return this.ActLike<T>();
    }
}

и использовать ее как

 var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
 var mc=new ClassWrapper<IMyData>(data);

 IMyData wrapped = mc.GetWrapper();

 DoStuff(wrapped);
 Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)mc.GetFieldsUsed())}");
0 голосов
/ 26 мая 2020

Если вы хотите знать, когда используется свойство, интерфейс типа INotifyPropertyChanged может сделать это за вас во время выполнения. Пример касается только уведомлений о записи (которые фактически изменили значение), но было бы тривиально расширить его до операций чтения и записи. Конечно, это не идеальный вариант, поскольку разные исполнения могут следовать разным путям кода, которые используют разные свойства. свойства могут быть актуальными . Это особенно верно для абстрактных типов и интерфейсов - часто интерфейс существует для этой функции. Если это одна из этих двух, вы также всегда можете предоставить свою собственную реализацию этих интерфейсов и абстрактного класса.

Я не могу избавиться от ощущения, что это проблема XY.

...