none
Callback from underlying Get Set methods using Reflection RRS feed

  • Question

  • Hi

    I have hundreds of properties in the Model class.

    is there a way to intercept or get a callback whenever a "get or set" is made on a particular property using reflection?
    i would like to try and achieve this without changing source code of the Model class.

    thanks

    public class Model { public int one { get; set; } }

    var model = new Model();

    model.one = 1;

    var one = model.one;


    Thursday, January 30, 2020 11:43 PM

All replies

  • One option is INotifyPropertyChanged

    The following uses a NuGet package JetBrains.Annotations but can be done without it too. The trick here is using [CallerMemberName] string propertyName = null.

    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using CommonPractice.Interfaces;
    using JetBrains.Annotations;
    
    namespace CommonPractice.BaseJetNotifyClasses
    {
        public class Person : INotifyPropertyChanged
        {
            private string _firstName;
            private string _lastName;
    
            public int Id { get; set; }
    
            public string FirstName
            {
                get => _firstName;
                set
                {
                    if (value == _firstName) return;
                    _firstName = value;
                    OnPropertyChanged();
                }
            }
    
            public string LastName
            {
                get => _lastName;
                set
                {
                    if (value == _lastName) return;
                    _lastName = value;
                    OnPropertyChanged();
                }
            }
    
            public override string ToString() => $"{FirstName} {LastName}";
            public event PropertyChangedEventHandler PropertyChanged;
    
            [NotifyPropertyChangedInvocator]
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    Another option is PropertyChanged.Fody on NuGet.

    [ImplementPropertyChanged]
    public partial class Person
    {
    }
    Using with Entity Framework


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange


    Friday, January 31, 2020 1:43 AM
    Moderator
  • Hi thanks for the reply

    As I have Hundreds of properties

    i was hoping not to have to expand each property like so:

      private string _one;
    
            public string One
            {
                get => _one;
                set
                {
                    if (value == _one) return;
                    _one = value;
                    OnPropertyChanged();
                }
            }
    I noticed this solution would work for Set method but not Get. it would seem strange if i called the OnPropertyChanged() for the Get method aswell.

    thanks

    Friday, January 31, 2020 8:40 PM
  • Hi Nz tribute,

    Thanks for your feedback.

    PropertyChanged.Fody injects code which raises the PropertyChanged event into property setters of classes which implement INotifyPropertyChanged.

    Besides, here's a related reference:

    What's the best way to handle updates only when a value has changed?

    Hope them could be helpful.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, February 3, 2020 12:11 PM
    Moderator
  • Just to clarify

    - Do you want notification when value of the property has changed like implementing INotifyPropertyChange support give? or

    - Do you want to be notified when value of property is get or set in general not just when property changes?

    Monday, February 3, 2020 12:29 PM
  • This cannot be done with reflection dynamically. Reflection allows you to evaluate the metadata and explicitly call members of an instance. It doesn't have any functionality built in that would auto-magically allow it to know that some arbitrary property is being set because reflection doesn't change the existing code. Since it cannot inject itself between 2 arbitrary lines of code to get notified reflection cannot solve this problem.

    The only way to do this without code modification is to use an instrumentation library that can rewrite your code to implement INotifyPropertyChanged or equivalent. But now you're paying the cost of instrumentation each time. A short time solution in my opinion.

    The correct approach as Karen mentioned is to implement INPC interface as that is exactly what this is designed for. I think there are some extensions floating around (or even some quick actions in VS 2019) that can take an existing type and convert it to implement INPC so you don't have to. Even with 100 properties it'll take less than 30 minutes because the code is boilerplate. You can do it custom or do like the configuration subsystem does and just use a dictionary to quickly replace properties. Either way it is minimal effort.

    Once you've implemented INPC you no longer need to worry about the performance overhead of reflection and it is easily discoverable and usable in UIs that support it. 


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, February 3, 2020 2:58 PM
    Moderator
  • Hi thanks for the reply

    As I have Hundreds of properties

    i was hoping not to have to expand each property like so:

      private string _one;
    
            public string One
            {
                get => _one;
                set
                {
                    if (value == _one) return;
                    _one = value;
                    OnPropertyChanged();
                }
            }
    I noticed this solution would work for Set method but not Get. it would seem strange if i called the OnPropertyChanged() for the Get method aswell.

    thanks

    There are Visual Studio tools that can assist with this but they are not free. For instance ReSharper which does this and much more.

    Note that I have no ties to ReShaper other than been using it for two years. I tend not to point to a third party paid product but ReSharper is a great product and might be worth looking at, they may or may not have a free trial, have not looked.

    When property notification is needed for a class simply create fields rather than properties. ReSharper has a function to create properties for each field.

    Example

    public DateTime BirthDate
    {
        get => _birthDate;
        set
        {
            if (value.Equals(_birthDate)) return;
            _birthDate = value;
            OnPropertyChanged();
        }
    }

    If the getter needs to have a body, ReSharper will not auto setup bodies for getters out of the box but by single clicking a property, right click there is an option to make that property get have a body.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Monday, February 3, 2020 3:31 PM
    Moderator