none
Wie generische Wrapper-Klasse erstellen? RRS feed

  • Frage

  • Hallo,
    ich habe zwei Klassen TestA und TestB und will die beiden generisch in einer dritten Klasse TestC wrappen.
    Wie erstelle ich eine Wrapper-Klasse TestC und rufe diese mit Typ TestA oder TestB auf?

    Alexander

    public class TestA { public string Name { get; set; } public List<int> Numbers { get; set; } } public class TestB {

    public enum DeviceType { Mobile, Direct } public DeviceType Type { get; set; } public int? Count { get; set; } }


    Freitag, 21. April 2017 12:49

Antworten

  • Hallo Alexander,

    grundsätzlich geht es mir wie Stefan, aber mal ins Blaue geraten: Suchst du vielleicht etwas wie einen Summentyp? Das heißt, du bildest eine Art Ober-Klasse aus TestA und TestB. Normalerweise würde sich so etwas in einer gemeinsamen Basis-Klasse oder einer gemeinsamen Schnittstelle wiederspiegeln; einige Programmiersprachen (C# (noch) nicht) können derartige Konstrukte jedoch auch zusätzlich ohne Vererbung implementieren. So beispielsweise in TypeScript:

    TestA | TestB

    C# kann das wie gesagt (noch) nicht und der beste Ansatz ist eine generische Container-Klasse:

    class SumType<TA, TB>{
      private TA _a;
      private TB _b;
    
      public TA A{
        get{
          if(this._a != null){
            return this._a;
          }
          throw new InvalidOperationException();
        }    
      }
      public TB B{
        get{
          if(this._b != null){
            return this._b;
          }
          throw new InvalidOperationException();
        }    
      }
    
      public bool IsA => this._a != null;
      public bool IsB => this._b != null;
    
      public SumType(A a){
        this.A = a;
      }
      public SumType(B b){
        this.B = b;
      }
    }

    Wobei man hier auch noch einen expliziten Cast-Operator einbauen könnte.

    Es läuft im Moment jedoch immer darauf hinaus, dass du das SumType-Objekt immer erst in TA oder TB casten musst, bevor du innere Member verwenden kannst.

    PS: Bei spezifisch angelegten SumType-Klassen kannst du auch noch mittels where einschränken, was TA und TB implementieren müssen. In dem Fall könntest du diese Member auch direkt nach außen hin sichtbar machen. Beispielsweise:

    public interface ILength{
      int Length{get;}
    }
    public class LengthSumType<TA, TB> : SumType<TA, TB>, ILength
        where TA : ILength
        where TB : ILength
    {
      public int Length{
        get{
          return this._a == null ? this._b.Length : this._a.Length;
        }
      }
    
      //Der Rest der Klasse wie bei SumType<TA, TB>, der einfachhei halber wird einfach davon geerbt
    
    //Die Basis-Konstruktoren aufrufen public LengthSumType(A a) : base(a) { } public LengthSumType(B b) : base(b) { } }

    Nun ist es egal, ob du LengthSumType mit einem TA oder TB befüllt hast: Length kannst du immer abfragen. Spezifischere Member, die nicht von ILength vorgeschrieben werden, bedürfen jedoch noch immer einem abrufen der expliziten Klassen-Instanz.

    Viele Grüße, Tom Lambert - MVP, MCC und MSP
    Wozu Antworten markieren und Posts bewerten? Klicke hier
    Nützliche Links: .NET Quellcode | C#/VB.NET Konverter | GitHub Forum Samples | Account bestätigen (Verify Your Account)
    Ich: Webseite | Facebook | Twitter | Code Snippets | GitHub



    Montag, 24. April 2017 12:40
    Moderator

Alle Antworten

  • Hallo Alexander,

    ehrlich gesagt habe ich nicht verstanden, was Du machen willst.

    Da die beiden Klassen ja rein gar nichts gemeinsam haben, kannst Du schlecht eine Klasse erstellen, in der Du A oder B wrappst. Welchen sinn sollte das auch haben?

    Beschreib doch mal genauer, was Du eigentlich vorhast.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Freitag, 21. April 2017 13:03
    Moderator
  • Hallo Stefan,

    mir geht es allgemein um die Technik, wie eine Wrapperklasse generisch erstellt wird. Die beiden Beispiele sind vielleicht unglücklich gewählt.

    Alexander

    Sonntag, 23. April 2017 17:35
  • Hallo Alexander,

    auch deine neue Anforderung ist etwas unglücklich gewählt, da ich, ehrlich gesagt, immer immer noch nicht weiß, was Du willst.

    Wenn Du mehrere Klassen mit gemeinsamen Eigenschaften und Methoden austatten willst, um diese dann an verschiedenen Stellen einheitlich behandeln zu können, bietet sich bspw. je nach genauer Anforderung, ein Interface an.

    Ansonsten kannst Du auch eine Basisklasse erstellen und von dieser ableiten.

    Oder irgendwas anderes aber genau dafür müsste man exakt wissen, was Du eigentlich willst.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community


    Montag, 24. April 2017 06:47
    Moderator
  • Hallo Alexander,

    grundsätzlich geht es mir wie Stefan, aber mal ins Blaue geraten: Suchst du vielleicht etwas wie einen Summentyp? Das heißt, du bildest eine Art Ober-Klasse aus TestA und TestB. Normalerweise würde sich so etwas in einer gemeinsamen Basis-Klasse oder einer gemeinsamen Schnittstelle wiederspiegeln; einige Programmiersprachen (C# (noch) nicht) können derartige Konstrukte jedoch auch zusätzlich ohne Vererbung implementieren. So beispielsweise in TypeScript:

    TestA | TestB

    C# kann das wie gesagt (noch) nicht und der beste Ansatz ist eine generische Container-Klasse:

    class SumType<TA, TB>{
      private TA _a;
      private TB _b;
    
      public TA A{
        get{
          if(this._a != null){
            return this._a;
          }
          throw new InvalidOperationException();
        }    
      }
      public TB B{
        get{
          if(this._b != null){
            return this._b;
          }
          throw new InvalidOperationException();
        }    
      }
    
      public bool IsA => this._a != null;
      public bool IsB => this._b != null;
    
      public SumType(A a){
        this.A = a;
      }
      public SumType(B b){
        this.B = b;
      }
    }

    Wobei man hier auch noch einen expliziten Cast-Operator einbauen könnte.

    Es läuft im Moment jedoch immer darauf hinaus, dass du das SumType-Objekt immer erst in TA oder TB casten musst, bevor du innere Member verwenden kannst.

    PS: Bei spezifisch angelegten SumType-Klassen kannst du auch noch mittels where einschränken, was TA und TB implementieren müssen. In dem Fall könntest du diese Member auch direkt nach außen hin sichtbar machen. Beispielsweise:

    public interface ILength{
      int Length{get;}
    }
    public class LengthSumType<TA, TB> : SumType<TA, TB>, ILength
        where TA : ILength
        where TB : ILength
    {
      public int Length{
        get{
          return this._a == null ? this._b.Length : this._a.Length;
        }
      }
    
      //Der Rest der Klasse wie bei SumType<TA, TB>, der einfachhei halber wird einfach davon geerbt
    
    //Die Basis-Konstruktoren aufrufen public LengthSumType(A a) : base(a) { } public LengthSumType(B b) : base(b) { } }

    Nun ist es egal, ob du LengthSumType mit einem TA oder TB befüllt hast: Length kannst du immer abfragen. Spezifischere Member, die nicht von ILength vorgeschrieben werden, bedürfen jedoch noch immer einem abrufen der expliziten Klassen-Instanz.

    Viele Grüße, Tom Lambert - MVP, MCC und MSP
    Wozu Antworten markieren und Posts bewerten? Klicke hier
    Nützliche Links: .NET Quellcode | C#/VB.NET Konverter | GitHub Forum Samples | Account bestätigen (Verify Your Account)
    Ich: Webseite | Facebook | Twitter | Code Snippets | GitHub



    Montag, 24. April 2017 12:40
    Moderator
  • Hallo AlexanderRi,

    Das klingt für mich nach Mehrfachvererbung und die ist in C# nicht möglich, in C++ wäre das möglich.

    Ich denke das es auf ein Interface von Typ A und eines von Typ B hinaus läuft, welche von Typ C implementiert werden.


    - Gruß Florian

    Dienstag, 25. April 2017 09:02