Frage

ich eine Container-Klasse haben, die einen generischen Parameter hat, die zu einem gewissen Basisklasse beschränkt ist. Die Art des Ober geliefert ist ein Unter der Beschränkungsbasisklasse. Die Sub-Klasse verwendet Methode versteckt (neu) das Verhalten einer Methode aus der Basisklasse zu ändern (nein, ich kann es nicht machen virtuelle da es nicht mein Code). Mein Problem ist, dass die ‚neuen‘ Methoden nicht aufgerufen, der Compiler scheint der bereitgestellte Typ zu prüfen, die Basisklasse sein, nicht die Unter, als ob ich upcast es an der Basis hatte.

Klar bin ich Missverständnis etwas Grundsätzliches hier. Ich dachte, dass die generische where T: xxx eine Einschränkung war, kein upcast Typ.

Dieser Beispielcode im Grunde zeigt, was ich rede.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericPartialTest
{
    class ContextBase
    {
        public string GetValue()
        {
            return "I am Context Base: " + this.GetType().Name;
        }

        public string GetOtherValue()
        {
            return "I am Context Base: " + this.GetType().Name;
        }

    }

    partial class ContextSub : ContextBase
    {
        public new string GetValue()
        {
            return "I am Context Sub: " + this.GetType().Name;
        }
    }

    partial class ContextSub
    {
        public new string GetOtherValue()
        {
            return "I am Context Sub: " + this.GetType().Name;
        }
    }

    class Container<T> where T: ContextBase, new()
    {
        private T _context = new T();

        public string GetValue()
        {
            return this._context.GetValue();
        }

        public string GetOtherValue()
        {
            return this._context.GetOtherValue();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Simple");
            ContextBase myBase = new ContextBase();
            ContextSub mySub = new ContextSub();

            Console.WriteLine(myBase.GetValue());
            Console.WriteLine(myBase.GetOtherValue());
            Console.WriteLine(mySub.GetValue());
            Console.WriteLine(mySub.GetOtherValue());

            Console.WriteLine("Generic Container");
            Container<ContextBase> myContainerBase = new Container<ContextBase>();
            Container<ContextSub> myContainerSub = new Container<ContextSub>();

            Console.WriteLine(myContainerBase.GetValue());
            Console.WriteLine(myContainerBase.GetOtherValue());
            Console.WriteLine(myContainerSub.GetValue());
            Console.WriteLine(myContainerSub.GetOtherValue());


            Console.ReadKey();
        }
    }
}

Edit:

Ich denke, meine Verwirrung kommt aus, dass man dies tun

class SomeClass<T> where T: AnotherType, new()
{
    T foo = new T();     
}

Und ich erwartete T T zu sein, obwohl ich der Compiler verstehen T sehen würde als AnotherType der Schnittstelle mit. Ich nahm die Typisierung von T zur Laufzeit selbst passieren würde, wenn die Schnittstelle von T bei der Kompilierung festgelegt wurde. Die T foo Erklärung scheint hier irreführend, weil es wirklich tut,

AnotherType foo = new T();

Wenn ich verstehe, dass es nicht wirklich foo als Typ T erklärt wird, ist es verständlich, warum das new Methode Versteck würde nicht funktionieren.

Und das ist alles, was ich dazu zu sagen habe.

War es hilfreich?

Lösung

Methoden erklärt new keine Beziehung haben (aus Sicht des Compilers) Verfahren mit dem gleichen Namen / Unterschrift in der Basisklasse. Das ist einfach der Compiler den Weg von dem Sie verschiedene Methoden abgeleitet definieren Klassen, die eine Signatur mit einem Verfahren in ihrer Basisklasse Hierarchie teilen.

Jetzt, im Hinblick auf Ihren konkreten Fall erkennen, dass Generika zu einem einzigen Satz von Bytecode kompiliert hat, unabhängig von den Typen, die als generische Parameter geliefert werden . Als Ergebnis weiß der Compiler nur über das Verfahren und die Eigenschaften, die auf der generischen Typ T definiert sind -, dass der Basistyp Du in der generischen Einschränkung angeben würde. Der Compiler weiß nichts über die new Methoden in der abgeleiteten Typ, auch wenn Sie eine Instanz eines generischen Typs mit dem abgeleiteten Typ als Parameter erstellen. Daher ruft in der allgemeinen Klasse wird immer auf die Methoden des Basistypen gehen.

Es gibt eine Menge Verwirrung über neu / virtual / Override; nehmen Jon Skeet Antwort auf eine ähnliche Frage kann Ihnen auch helfen, zu verstehen, warum Ihre Implementierung verhält sich so, wie es der Fall ist.

Es gibt zwei Möglichkeiten für Sie zu arbeiten, um dieses Problem:

  1. Führen Sie einen bedingten Guss (basierend auf Laufzeittypinformationen) an dem abgeleiteten Typ (oder eine Schnittstelle) in der allgemeinen Klasse. Dies bricht Verkapselung und fügt eine unerwünschte Kopplung. Es ist auch zerbrechlich, wenn nur unzureichend umgesetzt.
  2. Definieren Sie eine Schnittstelle , die Sie in Ihrem generische Einschränkung verwenden, die die Methoden, die Sie interessieren aussetzt. Dies kann nicht möglich sein, wenn der Code von dem Sie Ableitung ist nicht etwas, was Sie ändern können.

Andere Tipps

Ich denke, diese Frage SO fragte ich kann Ihnen helfen. Siehe Jon Skeet Antwort gibt, warum es nicht möglich ist.

eine weitere Ebene hinzufügen - vererben Ihre generic nicht von der Dritten Klasse, sondern von einer neuen Klasse, die wiederum erbt von der dritten Partei. In dieser neuen Klasse können Sie die Methode in Frage, wie neue virtuelle definieren. Wenn alle Ihre Code niemals direkt auf den dritten Teil der Klasse verweist, sollte es funktionieren

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top