wake-up-neo.com

Warum eine öffentliche Methode in einer internen Klasse verwenden?

In einem unserer Projekte ist viel Code enthalten, der so aussieht:

internal static class Extensions
{
    public static string AddFoo(this string s)
    {
        if (!string.IsNullOrEmpty(s)) return s + "Foo";
        return "Foo";
    }
}

Gibt es einen expliziten Grund dafür außer "Es ist einfacher, den Typ später zu veröffentlichen"?

Ich vermute, dass es nur in sehr seltsamen Edge-Fällen (Reflektion in Silverlight) oder überhaupt nicht wichtig ist.

225
Eric Burcham

UPDATE: Diese Frage war das Thema meines Blogs im September 2014 . Danke für die tolle Frage!

Diese Frage wird auch im Compilerteam selbst heftig diskutiert.

Zunächst ist es ratsam, die Regeln zu verstehen. Ein öffentliches Mitglied einer Klasse oder Struktur ist ein Mitglied, auf das zugegriffen werden kann für alle, die auf den enthaltenden Typ zugreifen können. Ein öffentliches Mitglied einer internen Klasse ist also effektiv intern.

Sollten die Mitglieder einer internen Klasse, auf die Sie in der Versammlung zugreifen möchten, nun als öffentlich oder intern gekennzeichnet sein?

Meine Meinung ist: Markiere solche Mitglieder als öffentlich.

Ich benutze "public", um zu bedeuten, dass dieses Mitglied kein Implementierungsdetail ist. Ein geschütztes Mitglied ist ein Implementierungsdetail. Es gibt etwas, das benötigt wird, damit eine abgeleitete Klasse funktioniert. Ein internes Mitglied ist ein Implementierungsdetail. Etwas anderes in dieser Versammlung Inneres benötigt das Mitglied, um korrekt zu funktionieren. Ein öffentliches Mitglied gibt an, dass "dieses Mitglied die wichtigsten dokumentierten Funktionen darstellt, die von diesem Objekt bereitgestellt werden".

Grundsätzlich ist meine Einstellung: Angenommen, ich habe beschlossen, diese interne Klasse in eine öffentliche Klasse umzuwandeln. Dazu möchte ich genau eines ändern : die Zugänglichkeit der Klasse. Wenn das Verwandeln einer internen Klasse in eine öffentliche Klasse bedeutet, dass ich auch ein internes Mitglied in ein öffentliches Mitglied verwandeln muss, dann war dieses Mitglied Teil der öffentlichen Oberfläche der Klasse, und das sollte es auch waren in erster Linie öffentlich.

Andere sind anderer Meinung. Es gibt ein Kontingent, das besagt, dass sie einen Blick auf die Deklaration eines Mitglieds werfen und sofort wissen möchten, ob sie nur aus internem Code aufgerufen wird.

Leider klappt das nicht immer so gut; Beispielsweise müssen für eine interne Klasse, die eine interne Schnittstelle implementiert, die implementierenden Mitglieder weiterhin als öffentlich markiert sein, da sie Teil der öffentlichen Oberfläche der Klasse sind.

374
Eric Lippert

Wenn die Klasse internal ist, spielt es aus Sicht der Barrierefreiheit keine Rolle, ob Sie eine Methode internal oder public markieren. Es ist jedoch immer noch gut, den Typ zu verwenden, den Sie verwenden würden, wenn die Klasse public wäre.

Während einige gesagt haben, dass dies Übergänge von internal zu public erleichtert. Es dient auch als Teil der Beschreibung der Methode. Internal Methoden gelten normalerweise als unsicher für den uneingeschränkten Zugriff, während public Methoden als (meistens) freies Spiel gelten.

Indem Sie internal oder public wie in einer public -Klasse verwenden, stellen Sie sicher, dass Sie über die Art des erwarteten Zugriffs informieren und gleichzeitig die für die Erstellung des erforderlichen Vorgangs vereinfachen Klasse public in der Zukunft.

14
Guvante

Ich markiere meine Methoden häufig in internen Klassen als public anstatt als internal, da a) es keine Rolle spielt und b) ich internal verwende, um anzuzeigen, dass die Methode absichtlich internal ist (es gibt einen Grund, warum ich dies nicht offenlegen möchte Wenn ich eine interne Methode habe, muss ich den Grund dafür wirklich verstehen, bevor ich sie in eine öffentliche umwandle. Wenn ich mich mit einer öffentlichen Methode in einer internen Klasse befasse, muss ich wirklich darüber nachdenken, warum die Klasse ist intern im Gegensatz dazu, warum jede Methode intern ist.

10

Ich vermute, dass "es einfacher ist, den Typ später zu veröffentlichen?" ist es.

Die Scoping-Regeln bedeuten, dass die Methode nur als internal angezeigt wird - es spielt also keine Rolle, ob die Methoden als public oder internal markiert sind.

Eine Möglichkeit, die mir in den Sinn kommt, ist, dass die Klasse war public und später in internal geändert wurde und der Entwickler sich nicht die Mühe machte, alle Modifikatoren für die Barrierefreiheit der Methoden zu ändern.

8
Oded

In einigen Fällen kann es auch sein, dass der interne Typ eine öffentliche Schnittstelle implementiert, was bedeutet, dass alle auf dieser Schnittstelle definierten Methoden weiterhin als öffentlich deklariert werden müssen.

7
Trevor Pilley

Es ist dasselbe, die public-Methode wird wirklich als intern markiert, da sie sich in einer internen Klasse befindet, aber es hat einen Vorteil (wie Sie es getan haben), wenn Sie die Klasse als öffentlich markieren möchten, müssen Sie weniger Code ändern.

2
Mario Corchero

internal sagt, dass auf das Mitglied nur innerhalb derselben Assembly zugegriffen werden kann. Andere Klassen in dieser Assembly können auf die internal public Mitglied, kann aber nicht auf ein private oder protected Mitglied, internal zugreifen oder nicht.

0
Ryan P

Ich hatte heute tatsächlich damit zu kämpfen. Bisher hätte ich gesagt, dass alle Methoden mit internal markiert werden sollten, wenn die Klasse internal war, und alles andere als schlechte Codierung oder Faulheit in Betracht gezogen hätten, insbesondere in der Unternehmensentwicklung. Ich musste jedoch eine public -Klasse unterklassen und eine der folgenden Methoden überschreiben:

internal class SslStreamEx : System.Net.Security.SslStream
{
    public override void Close()
    {
        try
        {
            // Send close_notify manually
        }
        finally
        {
            base.Close();
        }
    }
}

Die Methode MUSS public sein, und es hat mich zu dem Gedanken gebracht, dass es wirklich keinen logischen Sinn macht, Methoden als internal festzulegen, es sei denn, sie müssen es wirklich sein, wie Eric Lippert sagte.

Bis jetzt habe ich nie wirklich darüber nachgedacht, ich habe es einfach akzeptiert, aber nach dem Lesen von Eric's Post habe ich wirklich nachgedacht und nach vielen Überlegungen macht es sehr viel Sinn.

0
Storm

Ich glaube, ich habe eine zusätzliche Meinung dazu. Zuerst habe ich mich gefragt, wie es sinnvoll ist, in einer internen Klasse etwas der Öffentlichkeit zu erklären. Dann bin ich hier gelandet und habe gelesen, dass es gut sein könnte, wenn Sie später beschließen, die Klasse auf öffentlich umzustellen. Wahr. Also, ein Muster hat sich in meinem Kopf gebildet: Wenn es das aktuelle Verhalten nicht ändert, dann sei freizügig und erlaube Dinge, die es nicht tun Sinnvoll (und tut nicht weh) im aktuellen Codezustand, aber später würde es, wenn Sie die Deklaration der Klasse ändern.

So was:

public sealed class MyCurrentlySealedClass
{
    protected void MyCurretlyPrivateMethod()
    {
    }
}

Nach dem "Muster", das ich oben erwähnt habe, sollte dies vollkommen in Ordnung sein. Es folgt der gleichen Idee. Es verhält sich wie eine private Methode, da Sie die Klasse nicht erben können. Wenn Sie jedoch die Einschränkung sealed löschen, ist sie weiterhin gültig: Die geerbten Klassen können diese Methode sehen, was ich unbedingt erreichen wollte. Aber du bekommst eine Warnung: CS0628, oder CA1047. Beide deklarieren ungefähr keine protected Mitglieder in einer sealed Klasse. Außerdem habe ich volle Übereinstimmung darüber gefunden, dass es sinnlos ist: Warnung 'Geschütztes Mitglied in versiegelter Klasse' (eine Singleton-Klasse)

Nach dieser Warnung und der damit verbundenen Diskussion habe ich beschlossen, in einer internen Klasse alles intern oder weniger zu machen, weil es mehr dieser Art von Denken entspricht und wir keine unterschiedlichen "Muster" mischen.

0
Hix

Es gibt einen Unterschied. In unserem Projekt haben wir viele Klassen intern erstellt, aber wir führen in einer anderen Assembly einen Komponententest durch. In unseren Assembly-Informationen haben wir InternalsVisibleTo verwendet, um der UnitTest-Assembly den Aufruf der internen Klassen zu ermöglichen. Mir ist aufgefallen, dass wir aus irgendeinem Grund keine Instanz mit Activator.CreateInstance in der Unit-Test-Assembly erstellen können, wenn die interne Klasse einen internen Konstruktor hat. Wenn wir den Konstruktor jedoch in public ändern, die Klasse jedoch noch intern ist, funktioniert sie einwandfrei. Aber ich denke, das ist ein sehr seltener Fall (wie Eric im ursprünglichen Beitrag gesagt hat: Reflection).

0
Farrah Jiang