-1

I'm attempting to create a 'Has Been Edited' tracker for my component classes, like this:

public class MyComponent : ObservableObject
{
    // If any changes are made to properties that have the InspectableAttribute, this becomes true.
    public bool HasBeenEdited
    {
        get => _hasBeenEdited;
        protected set
        {
            if (value == _hasBeenEdited)
            {
                return;
            }
            _hasBeenEdited = value;
        }
    }
    private bool _hasBeenEdited = false;

    [Inspectable]
    public string StringProperty
    {
        get => _stringProperty;
        set => SetProperty(ref _stringProperty, value);
    }
    private string _stringProperty = null;

    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyInfo propertyInfo = GetType().GetProperty(e.PropertyName);
        if (Attribute.IsDefined(propertyInfo, typeof(InspectableAttribute)))
        {
            HasBeenEdited = true;
        }
        base.OnPropertyChanged(e);
    }
}

However, now that I'm testing it, when my 'MyComponent' instances are being deserialised from Json, I get the following unhelpful exception:

Newtonsoft.Json.JsonSerializationException: Error setting value to 'StringProperty' on 'MyComponent'. Inner Exception: ArgumentNullException: Value cannot be null. Arg_ParamName_Name This exception was originally thrown at this call stack: System.Attribute.IsDefined(System.Reflection.MemberInfo, System.Type, bool) System.Attribute.IsDefined(System.Reflection.MemberInfo, System.Type) MyComponent.OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs) in MyComponent.cs ...

First of all, the error is obviously a bit typo'd. I'm not seeing a property to 'StringProperty'. I'm setting a property named StringProperty. But I doubt that's a real problem.

Second, this value can safely be set to null, and is in fact initialised as null.

When I remove the call to Attribute.IsDefined the issue stops, suggesting that's somehow the problem, but it's not clear how.

Thomas Slade
  • 129
  • 9
  • I can't repduce this using [`ObservableObject`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.toolkit.mvvm.componentmodel.ObservableObject?view=win-comm-toolkit-dotnet-7.0) from Microsoft.Toolkit.Mvvm, Version=7.1.0.0, see https://dotnetfiddle.net/MaXKYQ. Please [edit] your question to share a [mcve]. – dbc May 17 '23 at 19:44
  • I'm having trouble isolating exactly what the issue is, so I can't get a minimum reproducible example without literally posting all my code (which I can't do). What I want to know is why this error is so unhelpful. The inner exception reports that 'Value cannot be null. Arg_ParamName_Name' ... ? – Thomas Slade May 19 '23 at 11:03
  • To answer my own question here: It's because I had the build in Release rather than Debug, which was removing a lot of important debug info ... – Thomas Slade May 19 '23 at 11:25

1 Answers1

0

Figured this out.

The issue actually came from a location where I was setting a property incorrectly:

public class MyKeyedComponent : MyComponent
{
    public string Key
    {
        get =>  _key;
        set => SetKey(value);
    }
    private string _key;
    
    public void SetKey(string value)
    {
        SetProperty(ref _key, value);
        
        // Do other stuff after setting the key
    }
}

SetProperty uses the calling member as its third parameter (the propertyName) unless otherwise specified. I'm so used to calling SetProperty from within the actual property setter, that I forgot to do otherwise here.

As a result, my OnPropertyChanged override was intercepting the changing of a property named SetKey. That is a function, and no such property exists.

As mentioned in another comment, my difficulty debugging this was partly due to me building release rather than debug.

Thomas Slade
  • 129
  • 9