Laden...

Parameter(typ) von Init-Methode soll in der Unterklasse spezifischer sein

Erstellt von rollerfreak2 vor 13 Jahren Letzter Beitrag vor 13 Jahren 2.734 Views
rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren
Parameter(typ) von Init-Methode soll in der Unterklasse spezifischer sein

Hallo zusammen,

ich steh grad ein bisschen auf dem Schlauch. Ich hab eine Basis Klasse die mehrere virtual Methoden hat. Unter anderem eine void Init(object data). Nun erben mehrere Klassen diese Klasse und implementieren natürlich auch die Init Methode. Nun ist aber in den Unterklassen das object genauer spezifizierbar, daher dort sollte nicht object data zugelassen werden, sondern ein spezieller Type.

Kann ich die Init Methode der Basisklasse den Typ "data"(object) generisch angeben, ohne die ganze Basisklasse generisch machen zu müssen? Oder muss die ganze Basisklasse generisch definiert werden und in den unterklassen mit where T ... eingeschränkt werden?


public class Test<T>
{
    public virtual Init(T data)
    {

    }
}

Again what learned...

L
862 Beiträge seit 2006
vor 13 Jahren

Die Basisklasse muss generisch sein. Die Unterklassen können dann von einem genauer spezifierten Typ davon ableiten:


public class BaseClass<T>
{
    public virtual void Init(T obj)
    {
    }
}

public class MyIntClass : BaseClass<int>
{
    public override void Init(int obj)
    {
        ...
    }
}

1.044 Beiträge seit 2008
vor 13 Jahren

Hallo rollerfreak2,

was spricht dagegen, die Init-Methode der Basisklasse generisch zu machen? Damit hast du keinen Nachteil, nur Vorteile. In der abgeleiteten Klasse kann man dann mit _where _einschränken. Ob das direkt mit der Methode geht, weiß ich nicht. Das _where _kannst du andernfalls direkt an der Klasse angeben.

zero_x

U
282 Beiträge seit 2008
vor 13 Jahren

Das führt aber beim Substitutionsprinzip zu Problemen.

Nun gibt es in der Basisklasse Test eine Methode Init(object).

Eine abgeleitete Klasse TestDerived hat Init(Foo).

Nun übergebe ich TestDerived als Test irgendwohin und rufe dort Init(new Bar()) auf, weil bei Test ja Init alles haben kann. Dann knallt es.

Logisch möglich wäre es, den Rückgabetyp zu spezialisieren oder den Parameter zu verallgemeinern. Aber auch das ist in C# (zumnindest bis 3.5) nicht möglich. In Java / c++ geht es.

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Mir ist klar das es auf die weise funktioniert wie Lector es beschrieben hat. Ich dachte man kann eine Methode einer Klasse generisch machen, ohne die Klasse generisch zu definieren. Weil das in meinem UseCase gereicht hätte. Aber nach genaueren drüber nachdenken ist das eigentlich schon richtig so. Weil die Init Methode initialisiert die Klasse mit einem Bestimmten Typ. Also sollte die Klasse auf den Typ beschränkt sein und damit generisch definiert werden.

Danke für die schnellen Antworten.

Again what learned...

360 Beiträge seit 2005
vor 13 Jahren

Ich dachte man kann eine Methode einer Klasse generisch machen, ohne die Klasse generisch zu definieren.

Ja das kannst du auch:

public class MyClass {

    public void Init<T>(T parameter) {
    }

}

Oder war das nicht das was du meintest?

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Genau die Syntax habe ich gesucht. Jetzt stellt sich also nur noch die Frage was nun besser geeignet ist. Die Klasse selbst hält dieses T nicht, im Init wird das Object nur genommen um einige Services zu laden, es wird nicht gespeichert.

Daher Klasse generisch oder Methode generisch?


public class MyClass1 
{
    public void virtual Init<T>(T parameter) 
    {

    }
}

public class MyClass2 : MyClass1
{
   public override void Init<T>(T data)
   {
        //wie kann ich hier das T einschränken?
   }
}


public override void InitStructure<T>(T data) where T : object
//das geht nicht

public override void InitStructure<int>(int data)
//das geht auch nicht

Again what learned...

656 Beiträge seit 2008
vor 13 Jahren

Mal ins blaue gefragt: Wenn jede abgeleitete Klasse ein spezifisches Objekt braucht, warum gibts die Methode dann in der Basisklasse? Du kannst sie dort ja so oder so nicht aufrufen.

Unter der Annahme, dass es gehen würde:

class MyBase { public abstract void Init(object o); }
class MyDerived1 : MyBase { public override void Init(Foo f); }
class MyDerived2 : MyBase { public override void Init(Bar b); }

Was würde deiner Meinung nach passieren, wenn du

MyBase b1 = new MyDerived1(); b1.Init(new Bar());
MyBase b2 = new MyDerived2(); b2.Init(new Foo());
MyBase b3 = new MyDerived1(); b3.Init(new MyDerived2());

machst?

Richtig: MyBase kann nicht auf den Typen einschränken, weil sie logischerweise nicht über die abgeleiteten Klassen bescheid wissen kann/soll.

Einzige Lösung: Nicht abstrakt machen, spezifisch pro Klasse - aufrufen kannst dus ja so oder so nicht typisiert über die Base.
Oder vielleicht ein anderes Design für den Fall wählen.

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Wenn jede abgeleitete Klasse ein spezifisches Objekt braucht, warum gibts die Methode dann in der Basisklasse?

Es dient nur dafür das eine gewisse Structure eingehalten wird. Klar ich könnte auch ein Interface Implementieren für diese Init Methode, oder gar kein Interface und die Init einfach public in jede Klasse schreiben, aber ob das besser ist sein mal da hin gestellt.

Was würde deiner Meinung nach passieren, wenn du...

Das würde ja nicht gehen, denn MyDerived1 sollte nur Bar's initialisieren können. Wobei wir wieder beim Thema der generischen Klasse wären, den wenn die Klasse den Typ einschränkt macht das schon wieder Sinn.

Again what learned...

1.361 Beiträge seit 2007
vor 13 Jahren

Hi,

ich finde bei C# Generics und IDictionary gehts um was ganz ähnliches.

Nur haben wir dort nicht:

public class Test<T>
{
    public virtual Init(T data)  {//...}
}

sondern:


interface MyInterface<T> : where T : Typ
{
    void DoSomething(T typ);
}

Aber gleiche Problematik!
Generikas mit unterschiedlichen Typen sind einfach nicht zueinander kompatibel, insbesondere gibt es keinen natürlichen BasisTyp, mit dem das Substitutionsprinzip per default erfüllt wäre.
Lediglich in den seltenen Fällen der Return-Wert-Kovarianz, oder der Parameter-Kontravarianz kann man die wieder hinbiegen. Oder aber man führt künstlich einen zusätzlichen Basistyp ein - dem aber die Generizität und damit die typsichere Methode fehlt.

beste Grüße
zommi

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Sehr gut zusammen gefasst Zoomi.

Again what learned...

656 Beiträge seit 2008
vor 13 Jahren

Was würde deiner Meinung nach passieren, wenn du...

Das würde ja nicht gehen, denn MyDerived1 sollte nur Bar's initialisieren können.

Das wäre aber das Problem, weil mans könnte (MyBase nimmt object, nicht Bar).

Wobei wir wieder beim Thema der generischen Klasse wären, den wenn die Klasse den Typ einschränkt macht das schon wieder Sinn.

In dem Fall wäre vermutlich das generische Interface (wie von zommi angemerkt) sinnvoll. Andererseits aber auch wieder nicht, weil du aufgrund der Spezialisierung so oder so nicht generalisieren kannst.

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Jepp, genau so ist es. Allerdings finde ich immer noch das die generische Klasse an der Stelle auch greift.

Again what learned...