Frage

Was sind die besten Praktiken in Bezug auf die Verwendung und die Struktur der inneren Klassen in C #.

Zum Beispiel, wenn ich eine sehr große Basisklasse und zwei große innere Klassen sollte ich teilten sie in einzelne (Teil- Klasse) codefiles oder lassen Sie sie als eine sehr große unhandliche Codefile?

Auch ist es schlechte Praxis eine abstrakte Klasse zu haben, mit einer öffentlichen geerbt inneren Klasse?

War es hilfreich?

Lösung

Normalerweise behalte ich mir innere Klassen für einen von zwei Zwecken:

  1. öffentliche Klassen, die von ihren Eltern-Klasse abgeleitet werden, wo die übergeordnete Klasse eine abstrakte Basisimplementierung mit einer oder mehrer abstrakten Methoden ist und jede Unterklasse ist eine Implementierung, die eine spezifische Implementierung dient. nach Rahmen Design Lesung und Richtlinien Ich sehe, dass dies als „Vermeiden“ markiert ist, aber ich es in Szenarien ähnlich wie Aufzählungen - althogh dass wahrscheinlich ist, als auch einen schlechten Eindruck,

  2. Die inneren Klassen sind privat und sind Einheiten von Geschäftslogik oder auf andere Weise eng gekoppelt an ihre Elternklasse in einer Art und Weise, in der sie grundsätzlich gebrochen werden, wenn sie von einer anderen Klasse verbraucht oder verwendet wird.

Für alle anderen Fälle, die ich versuche, sie im gleichen Namensraum zu halten und die gleichen Zugang Ebene als Verbraucher / logisch Eltern -. Oft mit Namen, das etwas weniger freundlich als die „main“ Klasse

Auf große Projekte würden Sie überrascht sein, wie oft Sie zunächst können sich finden, den Aufbau einer stark gekoppelten Komponente, nur weil es erste ist oder primäre Zweck ist es logisch erscheinen - aber wenn Sie einen sehr guten oder technischen Grund, es zu sperren da unten und versteckt es aus Sicht dann ist wenig Schaden in die Klasse ausgesetzt wird, so dass andere Komponenten sie verbrauchen können.

Bearbeiten Beachten Sie, dass, obwohl wir über Unterklassen reden sie sein sollten mehr oder weniger gut gestaltet und lose gekoppelten Komponenten. Auch wenn sie privat und unsichtbar für die Außenwelt stark eine minimale „Oberfläche“ zwischen den Klassen zu halten werden die Wartbarkeit des Codes für eine zukünftige Erweiterung oder Veränderung erleichtern.

Andere Tipps

Ich habe das Buch nicht zur Hand, aber die Rahmen-Design-Richtlinien schlagen public innere Klassen, solange Clients müssen nicht auf die Klassennamen verweisen. private innere Klassen sind in Ordnung: niemand diese bemerken geht

.

Bad: ListView.ListViewItemCollection collection = new ListView.ListViewItemCollection();

Gut: listView.Items.Add(...);

In Bezug auf Ihre große Klasse: es ist in der Regel lohnt Aufspaltung etwas wie dies in kleinere Klassen, die jeweils mit einem bestimmten Stück Funktionalität. Es ist schwierig, es zu brechen zunächst, aber ich sage voraus, es wird Ihr Leben leichter macht später ...

Generell innere Klassen sollten nur von der Klasse private und verwendbar sein, die sie enthält. Wenn sie innere Klassen sehr groß sind, dass würde vorschlagen, sollten sie ihre eigenen Klassen sein.

Normalerweise, wenn Sie eine große innere Klasse haben ist es, weil die innere Klasse fest gekoppelt ist, um es Klasse enthält, und benötigt Zugriff auf seine privaten Methoden.

Ich denke, das eher subjektiv, aber ich würde spaltet sie wahrscheinlich in separaten Code-Dateien bis indem die „host“ Klasse Teil.

Nach wie dies tun, können Sie noch mehr Übersicht erhalten von Bearbeitung der Projektdatei macht die Dateien Gruppe wie Designer-Klassen in Windows Forms. Ich glaube, ich habe ein Visual Studio Addin gesehen, dass dies für Sie automatisch tut, aber ich weiß nicht mehr, wo.

EDIT:
Nach einiger Suche fand ich die Visual Studio-Add-In für dieses genannt VSCommands tun

In Bezug auf nur wie ein solches Tier zu strukturieren ...

Sie können die Teil-Klassen verwenden, um die Hauptklasse und die verschachtelten Klassen zu spalten. Wenn Sie dies tun, werden Sie geraten Dateien in geeigneter Weise zu nennen, so dass es offensichtlich ist, was los ist.

// main class in file Outer.cs
namespace Demo
{
  public partial class Outer
  {
     // Outer class
  }
}

// nested class in file Outer.Nested1.cs
namespace Demo
{
  public partial class Outer
  {
    private class Nested1
    {
      // Nested1 details
    }
  }
}

In der gleichen Weise, man oft (explizite) -Schnittstellen in einer eigenen Datei. z.B. Outer.ISomeInterface.cs anstatt der Editor Standard sie von #regioning.

Ihre Projekte Dateistruktur beginnt dann zu schauen, wie

   /Project/Demo/ISomeInterface.cs
   /Project/Demo/Outer.cs
   /Project/Demo/Outer.Nested1.cs
   /Project/Demo/Outer.ISomeInterface.cs

Normalerweise, wenn wir dies tun, es ist für eine Änderung der Builder-Muster.

Ich mag persönlich eine Klasse pro Datei haben, und die inneren Klassen als Teil dieser Datei. Ich glaube, innere Klassen der Regel sollte (fast immer) sein privat und sind ein Implementierungsdetail der Klasse. Nachdem sie in einer separaten Datei verwechselt Dinge, IMO.

Mit Codebereichen um die inneren Klassen wickeln und verstecken ihre Details funktionieren gut für mich, in diesem Fall, und halten die Datei von schwierig zu sein, mit zu arbeiten. Die Codebereiche halten die innere Klasse „versteckt“, und da es eine private Implementierung Detail ist, das ist in Ordnung mit mir.

Ich persönlich innere Klassen verwenden, um einige Konzepte und Operationen innerhalb einer Klasse nur intern verwendet verkapseln. So kann ich verschmutzen nicht, dass die Klasse nicht-öffentliche api und halten Sie die api sauber und kompakt.

Sie können die Vorteile von Teilklassen nehmen Sie die Definition dieser inneren Klassen in eine andere Datei für eine bessere orgnanization zu bewegen. VS nicht automatisch Gruppe Teilklassendateien für Sie bis auf einige der templatized Elemente wie ASP.NET, Windows Forms Formulare, etc. Sie müssen die Projektdatei und machen einige Änderungen in dort bearbeiten. Sie können dort an einen der bestehenden Gruppierung sehen, wie es gemacht wird. Ich glaube, es gibt einige Makros, die Sie gruppieren Teilklassendateien für Sie in der Lösung Explorer ermöglichen.

Meiner Meinung nach inneren Klassen, wenn überhaupt benötigt wird, soll klein und nur intern von dieser Klasse verwendet, gehalten werden. Wenn Sie Relfector auf dem .NET-Framework verwenden, werden Sie sehen, wie sie eine Menge verwendet, nur für diesen Zweck.

Wenn Sie Ihre innere Klassen sind zu groß bekommen würde ich sie auf jeden Fall bewegen sich in unterschiedliche Klassen / codefiles irgendwie wenn auch nur für Wartbarkeit. Ich habe einige vorhandenen Code zu unterstützen, wo jemand dachte, es war eine großartige Idee innerhalb innere Klassen innere Klassen zu verwenden. Es führte zu einer inneren Klassenhierarchie ausgeführt 4 - 5 Ebenen tief. Es erübrigt sich der Code zu sagen, ist undurchdringlich und nimmt im Alter zu verstehen, was Sie suchen auf.

Hier ein praktisches Beispiel für eine verschachtelte Klasse zu sehen, die Ihnen eine Vorstellung von ihrer Verwendung (hinzugefügt einig Unit-Test) geben könnten

namespace CoreLib.Helpers
{
    using System;
    using System.Security.Cryptography;

    public static class Rnd
    {
        private static readonly Random _random = new Random();

        public static Random Generator { get { return _random; } }

        static Rnd()
        {
        }

        public static class Crypto
        {
            private static readonly RandomNumberGenerator _highRandom = RandomNumberGenerator.Create();

            public static RandomNumberGenerator Generator { get { return _highRandom; } }

            static Crypto()
            {
            }

        }

        public static UInt32 Next(this RandomNumberGenerator value)
        {
            var bytes = new byte[4];
            value.GetBytes(bytes);

            return BitConverter.ToUInt32(bytes, 0);
        }
    }
}

[TestMethod]
public void Rnd_OnGenerator_UniqueRandomSequence()
{
    var rdn1 = Rnd.Generator;
    var rdn2 = Rnd.Generator;
    var list = new List<Int32>();
    var tasks = new Task[10];
    for (var i = 0; i < 10; i++)
    {
        tasks[i] = Task.Factory.StartNew((() =>
        {
            for (var k = 0; k < 1000; k++)
            {
                lock (list)
                {
                    list.Add(Rnd.Generator.Next(Int32.MinValue, Int32.MaxValue));
                }
            }
        }));
    }
    Task.WaitAll(tasks);
    var distinct = list.Distinct().ToList();
    Assert.AreSame(rdn1, rdn2);
    Assert.AreEqual(10000, list.Count);
    Assert.AreEqual(list.Count, distinct.Count);
}

[TestMethod]
public void Rnd_OnCryptoGenerator_UniqueRandomSequence()
{
    var rdn1 = Rnd.Crypto.Generator;
    var rdn2 = Rnd.Crypto.Generator;
    var list = new ConcurrentQueue<UInt32>();
    var tasks = new Task[10];
    for (var i = 0; i < 10; i++)
    {
        tasks[i] = Task.Factory.StartNew((() =>
        {
            for (var k = 0; k < 1000; k++)
            {
                    list.Enqueue(Rnd.Crypto.Generator.Next());
            }
        }));
    }
    Task.WaitAll(tasks);
    var distinct = list.Distinct().ToList();
    Assert.AreSame(rdn1, rdn2);
    Assert.AreEqual(10000, list.Count);
    Assert.AreEqual(list.Count, distinct.Count);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top