Frage

der folgende Vererbungsbaum gegeben, was wäre der beste Weg, um es in eine Art und Weise der Umsetzung, die funktioniert?

abstract class Foo<T> : IEnumerable<T>
{
    public abstract Bar CreateBar();
}

class Bar<T> : Foo<T>
{
    // Bar's provide a proxy interface to Foo's and limit access nicely.
    // The general public shouldn't be making these though, they have access
    // via CreateBar()
    protected Bar(Foo base)
    {
        // snip...
    }
}

class Baz<T> : Foo<T>
{
    public Bar CreateBar()
    {
        return new Bar(this);
    }
}

Dies schlägt mit:. 'Bar.Bar()' is inaccessible due to its protection level

Ich will nicht der Konstruktor Öffentlichkeit zu sein, nur Klassen, die von Foo erben sollte in der Lage sein Bars zu erstellen. Bar ist ein spezialisierter Foo, und jede Art von Foo sollte man erstellen können. Öffentliche interne ist eine ‚Option‘ hier, da die Mehrheit der vordefinierten Erweiterungen wird es sein, Foo intern in dem DLL, aber ich halte das für eine schlampige Antwort, da jeder, der entlang später kommt, die ihre eigene Art von Foo oder Baz schaffen wollen (was wahrscheinlich passieren wird) wird mit einer Standard-CreateBar() Implementierung geklebt werden, die möglicherweise nicht ihren Bedürfnissen entsprechen.

Vielleicht gibt es eine Möglichkeit, dies zu Refactoring, um es schön funktioniert? Ich schlage meinen Kopf an der Wand versuchen, dies so zu gestalten, es aber funktionieren wird.

Bearbeiten (Mehr Info):

Etwas konkreter: Foo implementiert IEnumerable und lange Geschichte kurz, Bar ist die gleiche Schnittstelle zur Verfügung stellt, sondern auf eine begrenzte Teilmenge dieses enumerable Objekts. Alle Foo sollte in der Lage sein, Teilmengen von sich selbst zu schaffen (dh. Bar) und gibt es zurück. Aber ich will nicht jeder haben, der jemals einen Foo implementieren will, darüber zu haben, sich Sorgen zu machen, weil Bar die proxying tun und sorgen sich um den Bereich zu begrenzen, etc.

War es hilfreich?

Lösung

Okay, neue Antwort:

  1. Split Bar in eine Schnittstelle und eine konkrete Klasse.
  2. Express die Öffentlichkeit abstrakte Methode in Bezug auf IBar.
  3. Stellen Bar eine private geschachtelte Klasse in Foo, Implementierung IBar. Geben Sie ihm einen internen Konstruktor, die Sie von Foo aufrufen können.
  4. eine geschützte Methode in Foo schreiben, die eine Instanz von Bar von sich selbst erzeugt. Klassen von Foo ableiten können diese verwenden, um die abstrakte Methode zu implementieren, wenn nur proxying gut genug ist, und Klassen mit komplizierteren Anforderungen können nur implementieren IBar direkt. Man könnte sogar die abstrakte Methode, um einen virtuellen ändern und eine neue Bar von „this“ standardmäßig erstellen.

EDIT: Eine Variante dazu zu machen sei Bar eine geschützt geschachtelte Klasse innerhalb Foo, mit einem öffentlichen Konstruktor. Auf diese Weise jede abgeleitete Klasse es zu instanziiert der Lage wäre, für sich selbst, aber keine unabhängige Klasse wäre in der Lage zu „sehen“, es überhaupt nicht. Sie würden immer noch die Schnittstelle von der Implementierung trennen müssen (so dass die Schnittstelle öffentlich sein kann), aber ich denke, das ist eine gute Sache sowieso.

Andere Tipps

Wäre es möglich, für Sie Baz eine verschachtelte Art in Bar zu machen? Das ist der einzige Weg, es mehr Zugang geben werde Bar, als es sonst haben. die gleiche Elternklasse nur zu haben, gibt es nur den Zugriff auf geschützte Mitglieder der Foo, und Foo hat keinen besonderen Zugang zu Bar. Ich vermute, es gibt auch andere gewundene Wege, dies zu tun mit verschachtelten Typen, aber es wird als sehr unangenehm für Wartungsingenieure wirklich.

Es ist durchaus ein ungeradees Design aber eine abgeleitete Klasse zu zwingen, eine Instanz einer anderen Klasse von der gleichen Basisklasse abgeleitet zu erstellen. Ist das wirklich das, was Sie brauchen? Vielleicht, wenn Sie in konkretisiert dies wäre es einfacher, mit alternativen Design zu entwickeln.

Sie können Bar Konstruktor durch eine verschachtelte Art innerhalb Foo zugreifen:

abstract class Foo<T> : IEnumerable<T>
{
  public abstract Bar<T> CreateBar();

  protected Bar<T> CreateBar(Foo<T> f) { return new FooBar(f); }

  private class FooBar : Bar<T> 
   { public FooBar(Foo<T> f) : base(f) {}   
   }
}

class Bar<T> : Foo<T>
{ protected Bar(Foo<T> @base) {}
}

class Baz<T> : Foo<T>
{
    public override Bar<T> CreateBar() 
    {
        return CreateBar(this);
    }
}

Vergessen Sie für einen Moment, ergibt sich, dass Bar von Foo. Wenn Sie dies tun, ist es wie das Problem klingt, ist „Wie kann ich es so machen, dass jede Unterklasse von Foo eine Bar schaffen kann, auch wenn die Unterklasse haben keinen Zugriff auf die Bar Konstruktor?“

Das ist ein ziemlich einfaches Problem zu lösen:

public class Foo
{
   protected static Bar CreateBarInstance()
   {
      return new Bar();
   }
   public virtual Bar CreateBar()
   {
      return CreateBarInstance();
   }
}

public class Bar
{
    internal Bar()
    {
    }
}

public class Baz : Foo
{
    public override Bar CreateBar()
    {
        Bar b = base.CreateBar();
        // manipulate the Bar in some fashion
        return b;
    }
}

Wenn Sie auf Garantie , dass die Unterklassen von Foo haben keinen Zugang zu Bar Konstruktor, setzen Sie sie in einer anderen Anordnung.

Nun abzuleiten Bar von Foo, es ist eine einfache Änderung:

public class Bar : Foo
{
    internal Bar()
    {
    }
    public override Bar CreateBar()
    {
        throw new InvalidOperationException("I'm sorry, Dave, I can't do that.");
    }

}

„Ich will nicht die Konstruktor Öffentlichkeit zu sein.“ Überprüfen.

„Nur Klassen, die von Foo erben sollten in der Lage seine Bar zu schaffen.“ Überprüfen.

„Jede Art von Foo sollte in der Lage sein, einen zu erstellen.“ Überprüfen Sie,

„Wer entlang später kommt, der will, um ihre eigene Art von Foo oder Baz schaffen (was wahrscheinlich passieren wird) wird mit einem Standard-CreateBar () -Implementierung geklebt werden, die nicht ihren Bedürfnissen entsprechen oder nicht.“ Das ist ziemlich stark abhängig von, was in der Foo.CreateBar () -Methode passieren muss, denke ich.

C # bietet keine direkte Entsprechung des Freundes Stichwort ++ C. Scheint, wie Ihr Design ist erforderlich, diese Art von Konstrukt.

In C ++ Sie, dass eine bestimmte Klasse Zugriff auf die privaten / geschützten Mitglieder einer anderen Klasse bezeichnen könnte unter Verwendung von „Freund“ hat. . Hinweis: das ist nicht die gleiche wie C # intern, Modifikator, den Zugriff auf alle Klassen innerhalb derselben Baugruppe gibt

an Ihrem Design Sehen, es scheint, dass Sie versuchen, etwas entlang der Linien zu tun, die den C ++ Stil Freund erfordern würden. Jon Skeet ist richtig, das übliche Design in C # für die Make-up ist eine verschachtelte Klasse zu verwenden.

Das Forum posten weiter erklärt und zeigt einige Beispiele dafür, wie dies zu tun.

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