Frage Wie ist dieses Feld null?


Ich bekomme eine Null-Ausnahme, aber das Feld wurde als leere Liste initialisiert. Wie könnte es also null sein?

Der Fehler tritt in der zweiten Zeile dieser Methode auf (bei _hydratedProperties):

protected virtual void NotifyPropertyChanged<T>(Expression<Func<T>> expression)
{
    string propertyName = GetPropertyName(expression);

    if (!this._hydratedProperties.Contains(propertyName)) { this._hydratedProperties.Add(propertyName); }
}

Und so wird das Feld deklariert:

public abstract class EntityBase<TSubclass> : INotifyPropertyChanged where TSubclass : class
{
    private List<string> _hydratedProperties = new List<string>();

So ist es eingestellt:

    public Eta Eta
    {
        get { return this._eta; }

        set
        {
            this._eta = value;
            NotifyPropertyChanged(() => this.Eta);
        }
    }

Dies ist die vollständige Klasse (mit den Kommentaren und nicht relevanten Teilen entfernt):

[DataContract]
public abstract class EntityBase<TSubclass> : INotifyPropertyChanged where TSubclass : class
{
    private List<string> _hydratedProperties = new List<string>();

    public bool IsPropertyHydrated(string propertyName)
    {
        return this._hydratedProperties.Contains(propertyName);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged<T>(Expression<Func<T>> expression)
    {
        string propertyName = GetPropertyName(expression);

        if (!this._hydratedProperties.Contains(propertyName)) { this._hydratedProperties.Add(propertyName); }

        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string GetPropertyName<T>(Expression<Func<T>> expression)
    {
        MemberExpression memberExpression = (MemberExpression)expression.Body;
        return memberExpression.Member.Name;
    }
}

Abgeleitete Klasse:

[DataContract]
public class Bin : EntityBase<Bin>
{
    private Eta _eta;

    [DataMember]
    public Eta Eta
    {
        get { return this._eta; }

        set
        {
            this._eta = value;
            NotifyPropertyChanged(() => this.Eta);
        }
    }
}

9
2017-12-17 16:48


Ursprung


Antworten:


Hier ist der Hinweis:

[DataContract]

Jep. DataContractSerializer tut nicht Rufen Sie einen beliebigen Konstruktor auf. Stattdessen verwendet es FormatterServices.GetUninitializedObject um das Objekt zu erzeugen, das deserialisiert werden soll. Dies umgeht den Konstruktoraufruf.

Dein Initialisierer:

private List<string> _hydratedProperties = new List<string>();

wird vom Compiler in einen impliziten Standardkonstruktor übersetzt.

Als Workaround können Sie verwenden ein Deserialisierungs-Callback mit OnDeserializingAttribute:

[DataContract]
public abstract class EntityBase<TSubclass> : INotifyPropertyChanged
    where TSubclass : class
{
    private List<string> _hydratedProperties;

    protected EntityBase()
    {
        Init();
    }

    private void Init()
    {
        _hydratedProperties = new List<string>()
    }

    [OnDeserializing]
    private void OnDeserializing(StreamingContext context)
    {
        Init();
    }

    // ... rest of code here
}

12
2017-12-17 17:09



Ich fand eine einfachere Antwort als Lucas. Ich bin mir nicht sicher, ob das wirklich besser ist, aber es ist einfach und es hat funktioniert. Alles was ich getan habe, war das hinzufügen DataMember Attribut für das Feld. Da dies angibt, dass das Feld Teil des Datenvertrags ist, ist es in die Serialisierung / Deserialisierung einbezogen und verursacht keinen Nullreferenzfehler mehr.

[DataContract]
public abstract class EntityBase<TSubclass> : INotifyPropertyChanged where TSubclass : class
{
    [DataMember]
    private List<string> _hydratedProperties = new List<string>();

    // More code here
}

1
2017-12-17 20:51