Kódszagú a C # belső kulcsszó?

Ebben a bejegyzésben azt fogom bemutatni, hogy miért gondolom, hogy a belső kulcsszó, ha az osztály tagjaira kerül, kódszag, és jobb alternatívákat javasol.

Mi a belső kulcsszó?

A C # -ban a belső kulcsszó használható egy osztályon vagy annak tagjain. Ez az egyik C # hozzáférés módosító. A belső típusok vagy tagok csak ugyanazon összeállítás fájljain belül érhetők el . (C # belső kulcsszó dokumentáció).

Miért van szükség a belső kulcsszóra?

„A belső hozzáférés gyakori használata az összetevő-alapú fejlesztésben van, mert lehetővé teszi az alkotóelemek egy csoportjának privát együttműködését anélkül, hogy ki lenne téve az alkalmazáskód többi részének . Például a grafikus felhasználói felületek kiépítésére szolgáló keretrendszer olyan Control és Form osztályokat biztosíthat, amelyek együttműködnek a belső hozzáférésű tagok használatával. Mivel ezek a tagok belsőek, nincsenek kitéve a keretet használó kódnak. " (C # belső kulcsszó dokumentáció)

Ezeket a felhasználási eseteket láttam, amikor a belső kulcsszót egy osztálytagnál használtam:

  • Hívja meg egy osztály privát funkcióját ugyanazon az összeállításon belül.
  • Egy privát funkció teszteléséhez jelölheti azt belsőnek, és az InternalsVisibleTo segítségével tegye ki a dll-t a teszt DLL-nek.

Mindkét eset kódszagnak tekinthető, mondván, hogy ennek a privát funkciónak nyilvánosnak kell lennie.

Lássunk néhány példát

Itt egy egyszerű példa. egy osztály egyik funkciója egy másik osztály privát funkciójához akar hozzáférni.

class A{ public void func1(){ func2(); } private void func2(){} } class B{ public void func(A a){ a.func2(); //Compilation error 'A.func2()' is inaccessible due to its protection level } }

A megoldás egyszerű - egyszerűen jelölje meg az A :: func2 elemet nyilvánosként.

Nézzünk egy kicsit összetettebb példát:

public class A{ public void func1(){} private void func2(B b){} } internal class B{ public void func3(A a){ a.func2(this); //Compilation error 'A.func2(B)' is inaccessible due to its protection level } }

Mi a baj? csak jelölje meg a func2-t olyan nyilvánosnak, mint korábban.

public class A{ public void func1(){ ... } public void func2(B b){ ...} // Compilation error: Inconsistent accessibility: parameter type 'B' is less accessible than method 'A.func2(B)' } internal class B{ public void func3(A a){ a.func2(this); } }

De nem tehetjük? B egy belső osztály, így nem lehet része egy nyilvános osztály nyilvános funkciójának aláírásában.

Ezeket a megoldásokat találtam, könnyedség szerint rendezve:

  1. Jelölje meg a függvényt a belső kulcsszóval
public class A{ public void func1(){ } internal void func2(B b){} } internal class B{ public void func3(A a){ a.func2(this); } }

2. Hozzon létre egy belső felületet

internal interface IA2{ void func2(B b); } public class A:IA2{ public void func1(){ var b = new B(); b.func3(this); } void IA2.func2(B b){} //implement IA2 explicitly because func2 can't be public } internal class B{ public void func3(A a){ ((IA2)a).func2(this); //use interface instead of class to access func2 } }

3. Bontsa ki az A.func2 fájlt egy másik belső osztályba, és használja az A.func2 helyett.

internal class C{ public void func2(B b){ //extract A:func2 to here } } public class A{ public void func1(){} private void func2(B b){ new C().func2(b); } } internal class B{ public void func3(){ //a is no longer needed new C().func2(this); //use internal class instead of private function } }

4. Válassza le a függvényt a belső osztályokról, és tegye nyilvánossá. Ez nagyban függ attól, hogy a függvény mit csinál a bemeneteivel. a belső osztályok leválasztása nagyon könnyű, nagyon nehéz és akár lehetetlen is (anélkül, hogy tönkretenné a formatervezést)

De nincs nyilvános osztályunk, interfészeket használunk ...

Nézzünk meg néhány valósabb példát:

public interface IA{ void func1(); } internal class A : IA { public void func1(){} private void func2(B b){} } internal class B{ public void func3(IA a){ a.func2(this); //Compilation error IA' does not contain a definition for 'func2' and no extension method 'func2' accepting a first argument of type 'IA' could be found } }

Lássuk, hogyan adaptálják az előző megoldásokat ehhez a példához:

  1. Funkció megjelölése a Belső lehetőséggel. ez azt jelenti, hogy osztályba kell leadni a függvény meghívásához, így ez csak akkor működik, ha az A osztály az egyetlen, amely megvalósítja az interfészt , vagyis az IA-t nem csúfolják a tesztek, és nincs egy másik gyártási osztály, amely megvalósítja az IA-t .
public interface IA{ void func1(); } internal class A : IA { public void func1(){} internal void func2(B b){} } internal class B{ public void func3(IA a){ ((A)a).func2(this); //cast to A in order to accses func2 } }

2. Hozzon létre egy belső felületet, amely kiterjeszti a nyilvános felületet.

internal interface IExtendedA : IA{ void func2(B b); } public interface IA{ void func1(); } internal class A : IExtendedA { public void func1(){} public void func2(B b){} } internal class B{ public void func3(IExtendedA a){ a.func2(this); } }

3. Bontsa ki az A.func2 fájlt egy másik belső osztályba, és használja az A.func2 helyett.

4. Válassza le a függvényt a belső osztályokról, és adja hozzá a nyilvános felülethez.

Láthatjuk, hogy a belső kulcsszó a legkönnyebb megoldás , de vannak más megoldások is, amelyek az OOP hagyományos építőköveit használják: osztályok és interfészek . Láthatjuk, hogy a 2. megoldás - egy belső felület hozzáadása nem sokkal nehezebb, mint a függvény belső kulcsszóval történő megjelölése.

Miért ne használná a belső kulcsszót?

Amint azt az előző példákban bemutattam, a belső kulcsszó használata a legegyszerűbb megoldás . De a jövőben nehéz dolgai lesznek, ha:

  • Helyezze át az A nyilvános osztályt egy másik DLL-be (mivel a belső kulcsszó már nem vonatkozik ugyanarra a dll-re)
  • Hozzon létre egy másik gyártási osztályt, amely megvalósítja az IA-t
  • Gúny IA tesztekben

Gondolhatod: „De ez csak egy kódsor, én vagy bárki más szükség esetén könnyen megváltoztathatja”. Most van egy kódsor, amely így néz ki:

((MyClass)a).internalFunction

de ha másoknak is meg kell hívniuk ezt a függvényt, akkor ezt a sort másolni fogják a DLL-be.

Következtetésem

Azt hiszem, egy osztály tagjának a belső kulcsszóval való megjelölése kódszag . A fent bemutatott példákban ez a legegyszerűbb megoldás, DE problémákat okozhat a jövőben. A belső felület létrehozása majdnem ugyanolyan egyszerű és egyértelműbb.

Hasonlítsa össze a C ++ értékkel

The C++ “friend” keyword is similar to the C# internal keyword. It allows a class or a function to access private members of a class. The difference is it allows access to specific class or function and notall the classes in the same DLL. In my opinion, this is a better solution than the C# internal keyword.

Further Reading

Practical uses for the "internal" keyword in C#

Why does C# not provide the C++ style 'friend' keyword?