2016-08-01 22 views
3

Ich versuche, die Benachrichtigung über Änderungen an den Eigenschaften eines Objekts über eine IObservable<T> zu verallgemeinern, aber das ist neben dem Punkt der Frage. Der Punkt der Frage ist: die folgende Zuordnung I meldet eine ungültige Kovarianz Fehler machen:Covariant Zuordnung funktioniert nicht

protected virtual void OnPropertyChanged<T>(
         string propertyName, 
         T oldValue, T newValue) 
{ 
    IPropertyChangedNotification<Student, object> notification = 
     new PropertyChangedNotification<Student, T>(this, 
     propertyName, oldValue, newValue); 

    ... 
} 

Dies berichtet:

Cannot implicitly convert type PropertyChangedNotification<UsingSubjectToWatchProperty.Student, T> to IPropertyChangedNotification<UsingSubjectToWatchProperty.Student, object> . An explicit conversion exists (are you missing a cast?)

Dies ist die komplette Code:

class Student 
{ 
    private ISubject<IPropertyChangedNotification<Student, object>> _subject = 
     new Subject<IPropertyChangedNotification<Student, object>>();; 
    private string _name = null; 

    public string Name 
    { 
     get 
     { 
      return _name; 
     } 
     set 
     { 

      var oldValue = _name; 
      _name = value; 

      OnPropertyChanged<string>("Name", oldValue, _name); 
     } 
    } 

    protected virtual void OnPropertyChanged<T>(string propertyName, T oldValue, T newValue) 
    { 
     IPropertyChangedNotification<Student, object> notification = 
      new PropertyChangedNotification<Student, T>(this, 
      propertyName, oldValue, newValue); 

     _subject.OnNext(notification); 
    } 
} 

public class PropertyChangedNotification<TDeclaringType, TPropertyType> 
    : IPropertyChangedNotification<TDeclaringType, TPropertyType> 
{ 
    public PropertyChangedNotification(TDeclaringType declaringObject, 
     string propertyName, 
     TPropertyType oldValue, 
     TPropertyType newValue) 
    { 
     DeclaringObject = declaringObject; 
     PropertyName = propertyName; 
     OldValue = oldValue; 
     NewValue = newValue; 
    } 

    public TDeclaringType DeclaringObject { get; set; } 
    public string PropertyName { get; set; } 

    public TPropertyType OldValue { get; protected set; } 
    public TPropertyType NewValue { get; protected set; } 
} 

public interface IPropertyChangedNotification<TDeclaringType, out TPropertyType> 
{ 
    TDeclaringType DeclaringObject { get; set; } 
    string PropertyName { get; set; } 

    TPropertyType OldValue { get; } 
    TPropertyType NewValue { get; } 
} 

PS : Dies ist kein Produktionscode. Üben Sie einfach Sachen.

+1

''! = ''. Warum brauchst du das erste? Verwenden Sie einfach 'var'. – Sinatr

+0

Wie angegeben "Objekt"! = 'T'. Als eine Reihe von Seitennoten; Versuchen Sie, die Verwendung von Themen zu vermeiden. Und aus Interesse heraus, INPC-Ereignisse in Observable-Sequenzen zu verwandeln, wurde ein Dutzend Wege gelöst ;-) Hier sind ein paar kostenlose https://github.com/LeeCampbell/RxCookbook/blob/master/Model/PropertyChange.md –

+0

@LeeCampbell: Danke du, Lee. Ich habe deinen Artikel gelesen und es genossen. Ich habe versucht, es auf meine Weise zu tun. Ich versuche, alle Arten von Permutationen und Kombinationen zu machen und alle Beispiele in deinem Buch zu machen und dann noch einige, die ich alleine erfinde. :-) –

Antwort

5

Kovarianz und Kontravarianz werden nur für Referenztypen unterstützt (um einen Werttyp in einen Object umzuwandeln, müsste dieser in einem Rahmen dargestellt werden).

So würden Sie T-class beschränken müssen:

void OnPropertyChanged<T>(string propertyName, T oldValue, T newValue) 
    where T : class { ... } 

Alternativ können Sie auch nur new PropertyChangedNotification<Student, object>() nutzen könnten.

public interface IPropertyChangedNotification<TDeclaringType> 
{ 
    TDeclaringType DeclaringObject { get; set; } 
    string PropertyName { get; set; } 
} 

public interface IPropertyChangedNotification<TDeclaringType, out TPropertyType> 
    : IPropertyChangedNotification<TDeclaringType> 
{ 
    TPropertyType OldValue { get; } 
    TPropertyType NewValue { get; } 
} 

dann verwenden, in den Subject (da Sie es zu einem Beton gegossen müßten sowieso eingeben, wenn Sie sich vorher anmelden):

würde Eine dritte Möglichkeit eine Schnittstelle ohne TProperty haben seine

ISubject<IPropertyChangedNotification<Student>> 
+0

Bummer! Gibt es eine * kostengünstige * Möglichkeit, dies zu tun? –

+0

Hängt davon ab, was du mit * preiswert * meinst. Beide Alternativen, die ich vorgeschlagen habe, sind nicht teuer. Warum muss die Benachrichtigungsklasse getippt werden? Sie müssen eine Besetzung verwenden, wenn Sie trotzdem abonnieren. –

+0

Sie haben Recht. Ich habe das vergessen. –