0

I already know that C# provides internal modifier:

internal: The type or member can be accessed by any code in the same assembly, but not from another assembly. --- Quoted from this official document

And I also understand what is an assembly. It is basically a DLL or EXE.

Now, how can we be sure all our internal things will actually be compiled into the same assembly? The reason I ask this, is because I got an impression from here that the build process can be very flexible, different source file can potentially be compiled into different assemblies:

csc /target:library /out:MathLibraryPart1.DLL Add.cs
csc /target:library /out:MathLibraryPart2.DLL Mult.cs

to a point that we would even need a way to detect whether a file is in a particular assembly.

Put it in another way, if I already wrote my library with internal modifier here and there and then commit my code, but then the eventual binary output may or may not work as intended, due to the different way to build my source code. That doesn't sound right to me. Unless, the way to build my source code is (forced to become) also an integral part of my project and need to be checked into my code repo. Is that the case?

Community
  • 1
  • 1
RayLuo
  • 17,257
  • 6
  • 88
  • 73

2 Answers2

2

The build is deterministic, is the result of running VS builder or MSBuild on the solution file and the project files. They define strictly what assemblies are produced, there is no flexibility there. The general rule is "one .csproj file produces one assembly". And one .cs file belongs to one .csproj.

As for you modifying the access of a method or type to internal and then discovering at runtime that something is broken, you can rest assured: the discovery occurs at compile time. Your code won't even compile anymore.

Also, your binary 'may or may not work' seems like you're missing basic unit tests. Add unit tests, make them part of your build, and then you'll know if the code works or not (at least the part that is tested). Integration tests also help. Get started with developer testing tools.

Also, read Code Complete. So many of your questions were answered years ago and is sad to see them come back again and again.

Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
  • Lucky that I did write unit test. :-) By "may or may not work", I mean "if using a CLI compiler, would my code be possibly compiled in a different way, then some of the internal entities might become unaccessable?". Hence this question. Besides, wouldn't it actually be a good sign that a C# programmer in his first several weeks into this language is willing to think into this kind of details? Still thank you for your hint, and I upvoted your answer. – RayLuo Apr 14 '17 at 09:12
  • "if using a CLI compiler" is the key question. Who would do such thing, and why? If is your project end-to-end, then you must have in place a an automated, reproducible build process. While it may consist of batch files invoking CLI compiler, this would be highly unusual for C# code. So lets assume is a .csproj, and then need not worry about CLI. If you're worried about releasing your code as a library, in C# community libraries are consumed as pre-built assemblies, best released as NuGet packages. – Remus Rusanu Apr 14 '17 at 09:17
  • If worried about releasing your library as individual source code files and consumers mis-using them, is an impossible to defend position. You should absolutely not embed runtime code to check for what is basically, a badly compiled binary, *especially* when the bad usage will be caught by compiler (reference to `internal` members). – Remus Rusanu Apr 14 '17 at 09:19
  • "a good sign that a C# programmer in his first several weeks into this language is willing to think into this kind of details" yes, absolutely a good sign and keep it up :) – Remus Rusanu Apr 14 '17 at 09:21
  • And the reason why I go at length talking about runtime checks is it because *it is* possible to invoke an `internal` method from outside your assembly: http://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke-a-private-method . But one should not worry about such, the caller then assumes the risks of doing something not allowed, and he knows is doing so because he goes to extra lengths to actually do it.. – Remus Rusanu Apr 14 '17 at 09:25
1

Thanks for the hint (and motivation) from @Remus-Rusanu, I think the best way to understand this is do a hands-on experiment.

//File: foo.cs namespace Space { public class FooClass { public static int Foo() {return BarClass.Bar();} } }

//File: bar.cs namespace Space { internal class BarClass { public static int Bar() {return 123;} } }

Now, attempt to compile these 2 files into separated assemblies would not compile, which is a correct behavior:

csc /target:library /out:foo.dll foo.cs

error CS0103: The name 'Bar' does not exist in the current context

Compiling them together, you will get the library, and then all the internals inside this dll will work as expected.

csc /target:library /out:foobar.dll foo.cs bar.cs

# It will generate foobar.dll

So this clarifies my previous question. Yes, we can be sure that "all our internal things will actually be compiled into the same assembly", because otherwise the compile attempt would fail.

RayLuo
  • 17,257
  • 6
  • 88
  • 73