Ich möchte eine Wrapper-Klasse für einen anderen Typ erstellen. Dies funktioniert bis zu dem Punkt, wo es notwendig ist, dass (Referenz) -gleiche Objekte (Referenz) -gleiche Wrapper haben müssen.Adapter/Wrapper und gleiche Referenzen
Ein Beispiel:
public interface ITest<T>
{
T GetInstance(bool createNew);
}
public class Test : ITest<Test>
{
private static Test instance;
public Test GetInstance(bool createNew)
{
if (instance == null || createNew)
{
instance = new Test();
}
return instance;
}
}
public class TestWrapper : ITest<TestWrapper>
{
private readonly Test wrapped;
public TestWrapper(Test wrapped)
{
this.wrapped = wrapped;
}
public TestWrapper GetInstance(bool createNew)
{
return new TestWrapper(wrapped.GetInstance(createNew));
}
}
Test.GetInstance
kehrt immer die gleiche Instanz, solange der Parameter createNew
ist false
. Im Gegensatz dazu gibt TestWrapper.GetInstance
immer eine neue Instanz zurück.
Da ich Test
durch TestWrapper
ersetzen kann, suche ich nach einer Lösung, so dass der Wrapper am Ende nur eine neue Instanz zurückgibt, wenn Test eine neue Instanz zurückgibt. Der TestWrapper sollte jedoch keine Kenntnisse über die Interna von Test haben.
Der Testcode ist
private static void RunTest<T>(ITest<T> cls)
{
var i1 = (ITest<T>)cls.GetInstance(false);
var i2 = (ITest<T>)cls.GetInstance(false);
var i3 = (ITest<T>)cls.GetInstance(true);
var dic = new Dictionary<ITest<T>, bool>();
if (!dic.ContainsKey(i1)) dic.Add(i1, false); else dic[i1] = true;
if (!dic.ContainsKey(i2)) dic.Add(i2, false); else dic[i2] = true;
if (!dic.ContainsKey(i3)) dic.Add(i3, false); else dic[i3] = true;
Console.WriteLine(string.Join(", ", dic.Select(a => a.Value.ToString())));
}
Das gewünschte Ergebnis ist
True, False
und das ist, was man bekommt, wenn man new Test()
dieses Verfahren durchläuft. Wenn Sie new TestWrapper(new Test())
passieren, werden Sie
False, False, False
erhalten eine Lösung ist auf einem einfachen Cache basiert (Dictionary<Test, TestWrapper>
) - aber damit würde ich viele der Instanzen im Speicher halten, ohne sie jede weitere Verwendung (und der GC konnte diese Instanzen nicht sammeln, da es eine Referenz gibt, die sie enthält).
spielte ich mit WeakReferences
ein bisschen herum, aber ich kann nicht einen Schlüssel erkennen, dass ich die WeakReference
speichern können - also muss ich durch die Cache-Liste durchlaufen und für die richtige Instanz suchen, die langsam ist. Außerdem muss ich diese Lösung für jedes Mitglied implementieren (mit seinem eigenen Cache), was keine gute Lösung zu sein scheint ...
Ich hoffe, ich habe mein Problem ausreichend erklärt;) Meine Fragen sind also:
ist es eine Möglichkeit,(diese Frage ist nicht lohnend)object.ReferenceEquals
zu betrügen- was kann ich (als Schlüssel für den Cache) als Kennung für eine Objektinstanz verwenden (so kann ich
WeakReference
verwenden) - gibt es einen besseren Weg, um einen echten Adapter (wo ich kann ersetzen die adaptierten mit einem Adapter ohne Kopfschmerzen)
Ich habe keinen Zugriff auf die Test
Klasse und nur begrenzten Zugriff auf den Code, der es verwendet (ich bin in der Lage, so lange eine beliebige Instanz übergeben es implementiert ist die Schnittstelle)
Sie können nicht betrügen 'object.ReferenceEquals()', aber das ist der Grund, warum 'object.Equals()' virtuell ist und warum wir haben Dinge wie 'IEqualityComparer'. * Warum * brauchst du 'ReferenceEquals()', um hier wahr zurückzugeben? – StriplingWarrior
Haben Sie versucht, '==' operator zu überschreiben: 'public static bool operator == (T1 obj1, T2 obj2)'. – MaKCbIMKo
@StriplingWarrior: ** Ich ** brauche ReferenceEquals nicht, um wahr zu sein;). Die Laufzeit braucht es, um die Dinge richtig zu machen. Zum Beispiel wenn die Instanz als Schlüssel in einem Dictionary <> verwendet wird. –