ChatGPT解决这个技术问题 Extra ChatGPT

Practical uses for the "internal" keyword in C#

Could you please explain what the practical usage is for the internal keyword in C#?

I know that the internal modifier limits access to the current assembly, but when and in which circumstance should I use it?


r
ruffin

Utility or helper classes/methods that you would like to access from many other classes within the same assembly, but that you want to ensure code in other assemblies can't access.

From MSDN (via archive.org):

A common use of internal access is in component-based development because it enables a group of components to cooperate in a private manner without being exposed to the rest of the application code. For example, a framework for building graphical user interfaces could provide Control and Form classes that cooperate using members with internal access. Since these members are internal, they are not exposed to code that is using the framework.

You can also use the internal modifier along with the InternalsVisibleTo assembly level attribute to create "friend" assemblies that are granted special access to the target assembly internal classes.

This can be useful for creation of unit testing assemblies that are then allowed to call internal members of the assembly to be tested. Of course no other assemblies are granted this level of access, so when you release your system, encapsulation is maintained.


The InternalsVisibleTo attribute is a great help. Thank you.
My feeling is that from the moment you need internal, there's something wrong the design somewhere. IMHO, one should be able to use pure OO to solve all problems. At this very moment, I'm staring at about the one millionth use of internal in the .NET Framework source, barring my way to leverage the stuff they use themselves. Through the use of internal, they created a monolith that is superficially modular, but breaks down when you try to isolate stuff. Also, security is not an argument, as there's reflection to the rescue.
@GrimaceofDespair: Let me add a diagreeing comment here. I personally see internal as a very useful version of the "public" modifier in large multi-project solutions. Adding this modifier to a class in my subproject prohibits "random use" of this class by other subprojects in the solution and makes it possible for me to force the proper use of my library. If I will need to do some refactoring later on, I won't have to ask myself "wait, but why did that guy go and create an instance of the Point class which I only needed for my own purposes inside this particular computation"?
To put it in other way, if everyone would be relying on the internals of the SmtpClient, and at one moment a bug was discovered there, .NET would have serious problems to fix that bug, perhaps even keeping it around for a long time. I remember I read an amusing article once which described the length to which Windows developers had to go in order to keep "bugwards compatibility" with all the older programs that made use of various internal features and bugs. Repeating this error with .NET is not meaningful.
I think internal is WAY more useful than public. The only time you use public is when you explicitly are saying "Here, user - I'm supplying a useful function for you to use." If you're writing an application rather than a user library, everything should be internal because you're not trying to give people any functions at all to call externally. If you're writing a user library, then only the useful functions you expect to give to the user, maintain, support and keep around till the end of time should be public. Otherwise, make it internal.
E
Eric Lippert

If Bob needs BigImportantClass then Bob needs to get the people who own project A to sign up to guarantee that BigImportantClass will be written to meet his needs, tested to ensure that it meets his needs, is documented as meeting his needs, and that a process will be put in place to ensure that it will never be changed so as to no longer meet his needs.

If a class is internal then it doesn't have to go through that process, which saves budget for Project A that they can spend on other things.

The point of internal is not that it makes life difficult for Bob. It's that it allows you to control what expensive promises Project A is making about features, lifetime, compatibility, and so on.


Makes perfect sense. Just wish that we had the ability to override internal members, because we're all consenting adults here.
@EricLippert Not quite what I meant. If I inherit compiled code which has "internal" in it, I'm stuck, right? There's no way to simply tell the compiler "No, that other developer lied to you. You should trust me instead" unless I use reflection.
@cwallenpoole: If you're using code written by liars who write code you don't like then stop using their code and write your own code that you like better.
@EricLippert That was supposed to be tongue in cheek, I did not mean to offend. (I was mostly just trying to confirm that I am SOL in such cases).
@cwallenpoole: I'm not offended in the least. I'm offering good advice should you find yourself stuck in that unfortunate situation.
J
Joel Mueller

Another reason to use internal is if you obfuscate your binaries. The obfuscator knows that it's safe to scramble the class name of any internal classes, while the name of public classes can't be scrambled, because that could break existing references.


Pff. Looking at the bytecode with a disassembler will still make it pretty clear what the code does anyway. Obfuscators are barely a mild deterrent to anyone really trying to get into the internals. Never heard of a hacker who stopped just because he didn't get any useful function names.
so you don't lock your door when you sleep, because you've never heard of a thief stopped by a lock?
That's why I scramble class and variable names in the source code. You might be able to figure out what a PumpStateComparator is, but can you guess what a LpWj4mWE is? #jobsecurity (I don't do this, and please don't actually do this, internet people.)
J
Jeffrey L Whitledge

If you are writing a DLL that encapsulates a ton of complex functionality into a simple public API, then “internal” is used on the class members which are not to be exposed publicly.

Hiding complexity (a.k.a. encapsulation) is the chief concept of quality software engineering.


E
Edwin Jarvis

The internal keyword is heavily used when you are building a wrapper over non-managed code.

When you have a C/C++ based library that you want to DllImport you can import these functions as static functions of a class, and make they internal, so your user only have access to your wrapper and not the original API so it can't mess with anything. The functions being static you can use they everywhere in the assembly, for the multiple wrapper classes you need.

You can take a look at Mono.Cairo, it's a wrapper around cairo library that uses this approach.


I
Ilya Komakhin

Being driven by "use as strict modifier as you can" rule I use internal everywhere I need to access, say, method from another class until I explicitly need to access it from another assembly.

As assembly interface is usually more narrow than sum of its classes interfaces, there are quite many places I use it.


If you "use as strict modifier as you can" why not private then?
Since private is too strict when class properties/methods have to be accessed outside the class, and cases when they must be accessed from another asse,bly are not so often.
m
mattlant

I find internal to be far overused. you really should not be exposing certain functionailty only to certain classes that you would not to other consumers.

This in my opinion breaks the interface, breaks the abstraction. This is not to say it should never be used, but a better solution is to refactor to a different class or to be used in a different way if possible. However, this may not be always possible.

The reasons it can cause issues is that another developer may be charged with building another class in the same assembly that yours is. Having internals lessens the clarity of the abstraction, and can cause problems if being misused. It would be the same issue as if you made it public. The other class that is being built by the other developer is still a consumer, just like any external class. Class abstraction and encapsulation isnt just for protection for/from external classes, but for any and all classes.

Another problem is that a lot of developers will think they may need to use it elsewhere in the assembly and mark it as internal anyways, even though they dont need it at the time. Another developer then may think its there for the taking. Typically you want to mark private until you have a definative need.

But some of this can be subjective, and I am not saying it should never be used. Just use when needed.


I often build domain objects for which they have members that should be public to other domain objects within the same assembly. However, these same members should NOT be available to client code that is outside of the assembly. For situations like this, 'internal' is very appropriate.
P
Programmin Tool

Saw an interesting one the other day, maybe week, on a blog that I can't remember. Basically I can't take credit for this but I thought it might have some useful application.

Say you wanted an abstract class to be seen by another assembly but you don't want someone to be able to inherit from it. Sealed won't work because it's abstract for a reason, other classes in that assembly do inherit from it. Private won't work because you might want to declare a Parent class somewhere in the other assembly.

namespace Base.Assembly
{
  public abstract class Parent
  {
    internal abstract void SomeMethod();
  }

  //This works just fine since it's in the same assembly.
  public class ChildWithin : Parent
  {
    internal override void SomeMethod()
    {
    }
  }
}

namespace Another.Assembly
{
  //Kaboom, because you can't override an internal method
  public class ChildOutside : Parent
  {
  }

  public class Test 
  { 

    //Just fine
    private Parent _parent;

    public Test()
    {
      //Still fine
      _parent = new ChildWithin();
    }
  }
}

As you can see, it effectively allows someone to use the Parent class without being able to inherit from.


P
Prisoner ZERO

This example contains two files: Assembly1.cs and Assembly2.cs. The first file contains an internal base class, BaseClass. In the second file, an attempt to instantiate BaseClass will produce an error.

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

In this example, use the same files you used in example 1, and change the accessibility level of BaseClass to public. Also change the accessibility level of the member IntM to internal. In this case, you can instantiate the class, but you cannot access the internal member.

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

source: http://msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx


A
Aaron Powell

When you have methods, classes, etc which need to be accessible within the scope of the current assembly and never outside it.

For example, a DAL may have an ORM but the objects should not be exposed to the business layer all interaction should be done through static methods and passing in the required paramters.


c
cfeduke

A very interesting use of internal - with internal member of course being limited only to the assembly in which it is declared - is getting "friend" functionality to some degree out of it. A friend member is something that is visible only to certain other assemblies outside of the assembly in which its declared. C# has no built in support for friend, however the CLR does.

You can use InternalsVisibleToAttribute to declare a friend assembly, and all references from within the friend assembly will treat the internal members of your declaring assembly as public within the scope of the friend assembly. A problem with this is that all internal members are visible; you cannot pick and choose.

A good use for InternalsVisibleTo is to expose various internal members to a unit test assembly thus eliminating the needs for complex reflection work arounds to test those members. All internal members being visible isn't so much of a problem, however taking this approach does muck up your class interfaces pretty heavily and can potentially ruin encapsulation within the declaring assembly.


R
Rod

As rule-of-thumb there are two kinds of members:

public surface: visible from an external assembly (public, protected, and internal protected): caller is not trusted, so parameter validation, method documentation, etc. is needed.

private surface: not visible from an external assembly (private and internal, or internal classes): caller is generally trusted, so parameter validation, method documentation, etc. may be omitted.


Q
Quibblesome

Noise reduction, the less types you expose the more simple your library is. Tamper proofing / Security is another (although Reflection can win against it).


x
xofz

Internal classes enable you to limit the API of your assembly. This has benefits, like making your API simpler to understand.

Also, if a bug exists in your assembly, there is less of a chance of the fix introducing a breaking change. Without internal classes, you would have to assume that changing any class's public members would be a breaking change. With internal classes, you can assume that modifying their public members only breaks the internal API of the assembly (and any assemblies referenced in the InternalsVisibleTo attribute).

I like having encapsulation at the class level and at the assembly level. There are some who disagree with this, but it's nice to know that the functionality is available.


A
Andrew Kennan

One use of the internal keyword is to limit access to concrete implementations from the user of your assembly.

If you have a factory or some other central location for constructing objects the user of your assembly need only deal with the public interface or abstract base class.

Also, internal constructors allow you to control where and when an otherwise public class is instantiated.


K
Keith Williams

I have a project which uses LINQ-to-SQL for the data back-end. I have two main namespaces: Biz and Data. The LINQ data model lives in Data and is marked "internal"; the Biz namespace has public classes which wrap around the LINQ data classes.

So there's Data.Client, and Biz.Client; the latter exposes all relevant properties of the data object, e.g.:

private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }

The Biz objects have a private constructor (to force the use of factory methods), and an internal constructor which looks like this:

internal Client(Data.Client client) {
    this._client = client;
}

That can be used by any of the business classes in the library, but the front-end (UI) has no way of directly accessing the data model, ensuring that the business layer always acts as an intermediary.

This is the first time I've really used internal much, and it's proving quite useful.


F
Fredrik Mörk

There are cases when it makes sense to make members of classes internal. One example could be if you want to control how the classes are instantiated; let's say you provide some sort of factory for creating instances of the class. You can make the constructor internal, so that the factory (that resides in the same assembly) can create instances of the class, but code outside of that assembly can't.

However, I can't see any point with making classes or members internal without specific reasons, just as little as it makes sense to make them public, or private without specific reasons.


S
Steven A. Lowe

the only thing i have ever used the internal keyword on is the license-checking code in my product ;-)


S
Samik R

How about this one: typically it is recommended that you do not expose a List object to external users of an assembly, rather expose an IEnumerable. But it is lot easier to use a List object inside the assembly, because you get the array syntax, and all other List methods. So, I typically have a internal property exposing a List to be used inside the assembly.

Comments are welcome about this approach.


@Samik - could you please elaborate on, "typically it is recommended that you do not expose a List object to external users of an assembly, rather expose an IEnumerable." why is ienumerable preferred?
@Howiecamp: Mostly because IEnumerable gives a read-only access to the list, where as if you expose the list directly, it can be modified by clients (like delete elements etc.), which might be unintended.
Also, exposing a List or IList creates a contract that you will always allow (for example) fast random-access to the data. If someday you decide to change your method to use another collection, or no collection at all (yield return) you'll either have to create a List just to return a value, or break the contract by changing the return type of the method. Using a less specific return type gives you flexibility.
M
Matt Davis

Keep in mind that any class defined as public will automatically show up in the intellisense when someone looks at your project namespace. From an API perspective, it is important to only show users of your project the classes that they can use. Use the internal keyword to hide things they shouldn't see.

If your Big_Important_Class for Project A is intended for use outside your project, then you should not mark it internal.

However, in many projects, you'll often have classes that are really only intended for use inside a project. For example, you may have a class that holds the arguments to a parameterized thread invocation. In these cases, you should mark them as internal if for no other reason than to protect yourself from an unintended API change down the road.


So why not use private instead?
The private keyword can only be used on classes or structs that are defined within another class or struct. A class defined within a namespace can only be declared public or internal.
G
Grzenio

The idea is that when you are designing a library only the classes that are intended for use from outside (by clients of your library) should be public. This way you can hide classes that

Are likely to change in future releases (if they were public you would break client code) Are useless to the client and may cause confusion Are not safe (so improper use could break your library pretty badly)

etc.

If you are developing inhouse solutions than using internal elements is not that important I guess, because usually the clients will have constant contact with you and/or access to the code. They are fairly critical for library developers though.


y
yfeldblum

When you have classes or methods which don't fit cleanly into the Object-Oriented Paradigm, which do dangerous stuff, which need to be called from other classes and methods under your control, and which you don't want to let anyone else use.

public class DangerousClass {
    public void SafeMethod() { }
    internal void UpdateGlobalStateInSomeBizarreWay() { }
}

What are you trying to say? It's not very clear. At least not to me.