Reference has not compile-time usages - c#

I've been watching over the architecture view of our solution created by ReSharper, when I noticed some of the project references has no compile-time usages, does that mean I can change assemblies at runtime?

In simple terms, no compile-time usage means that your code will compile even if you remove the reference. You cannot directly derive anything regarding runtime from this statement. It might even be that your application runs perfectly fine if you just remove this reference. It might also be that your reference is somewhat obfuscated and the compiler doesn't know it. This could be because the reference is implementing interfaces that you compile against or you are looking for it manually at runtime (see Florians answer). You could probably also hide it with reflection if you really wanted to. But that would also need to load the assembly manually at runtime.
At compile-time, the compiler will link the new binaries to the corresponding code in the referenced assemblies. This will allow automatically loading the assembly at runtime. It will also copy const values to your assembly.
You can definitely change the referenced assembly between compile- and runtime, although you should tread very carefully. If method signatures changed, compile-time references will break.
At runtime, referenced assemblies will be loaded once you try to interact with them. Once an assembly is loaded, it cannot be unloaded directly. You can only unload AppDomains. So if you want to change assemblies at runtime, look into AppDomains.
So what could be an intended use of those non-compile-time references? The most common architecture that uses this was mentioned by Florian in the other answer: Plugins. Also other dependencies where you want to separate your code from the actual implementation via interfaces. Your project references without compile-time dependencies are then only used to deliver the implementation to the actual application. Otherwise you would need to add this to your delivery and debugging process, which can be a pain depending on your project.

Related

When to create and distribute "reference assemblies"?

C# 7.1 introduced a few new command line parameters to help create "reference assemblies". By documentation it outputs an assembly which:
have their method bodies replaced with a single throw null body, but include all members except anonymous types.
I've found an interesting note that it is more stable on changes:
That means it changes less often than the full assembly--many common development activities don't change the interface, only the implementation. That means that incremental builds can be much faster- ...
and that it is probably necessary for roslyn itself ..
We will be introducing a second concept, which is "reference assemblies" (also called skeleton assemblies). [---] They will be used for build scenarios.
.. whatever those "build scenarios" are for Roslyn.
I understand that for ordinary .NET assembly users, such assembly is probably smaller and slightly faster to load for reflection. Ok, but:
usually you also care about execution and the implementation assembly already contains all the data from reference assembly,
quite often you don't care about that minor performance difference on loading,
and most importantly - usually you don't have that stripped-down reference assembly available (distributed) at all.
It's usefulness seems rather niche.
So, I wonder about the general assembly producer side of things - when should one consider explicitly using those new compiler flags to create a reference assembly? Does it have a any practical use outside Roslyn itself at all?
The motivation for this feature is indeed build scenarios, but they're not specific to Roslyn; they're your build scenarios, too.
When you build your project, the build engine (MSBuild) needs to decide whether each output of the build is up to date with respect to its inputs. For example, if you don't change anything and just run build twice in a row, the second time doesn't need to invoke the C# compiler: the assembly was already correct.
Reference assemblies allow skipping the compile step for assemblies in more scenarios, so your builds can be faster. I think an example would help illustrate.
Suppose you have a solution containing B.exe that depends on A.dll.
The compiler command line for B would look something like
csc.exe /out:B.exe /r:..\A\bin\A.dll Program.cs
And its inputs would be
The source for B (Program.cs)
The assembly for A.
If you change the source of A and build your solution, the compiler must run for A, producing a new A.dll. Then, since A.dll is an input to the compilation of B, B has to be recompiled, too.
Using a reference assembly for A changes this slightly
csc.exe /out:B.exe /r:..\A\bin\ref\A.dll Program.cs
The input for A is now its reference assembly, rather than its implementation/normal assembly.
Since the reference assembly is smaller than the full assembly, that has a minor effect on build time all by itself. But that's not enough to justify this feature. What's important is that the compiler only cares about the public API surface of the passed-in references. If an internal implementation detail of the assembly has changed, assemblies that reference it do not need to be recompiled to pick up the new behavior. As #Hans Passant mentions in comments, this is how the .NET Framework itself can deliver compatible performance improvements and bug fixes on unchanged user code.
The benefit of the reference assemblies feature comes from the MSBuild work done to use them. Suppose you change an internal implementation detail in A but don't change its public interface. On the next build,
The compiler must run for A, because source files for A changed.
The compiler emits both A.dll (with the changed implementation) and ref\A.dll, which is identical to the previous reference assembly.
Since ref\A.dll is identical to the previous output, it does not get copied to A's output folder.
When it is time for B's compiler to run, it sees that none of its inputs have changed--neither B's own code, nor A's reference assembly, so the compiler doesn't have to run.
B then copies the updated A.dll to its output and is ready to run with the new behavior.
The effect of skipping downstream compilation can compound as you go along in a large solution--changing a comment in {ProjectName}.Utilities.dll no longer requires building everything!
Many changes involve changing both the public API surface and the internal implementation, so this change doesn't speed up all builds, but it does speed up many builds.

Using Code Contracts, why does ccrewrite require access to every runtime dependency?

I'm trying to use Code Contracts and I'm running into a problem that is blocking me. With Contract Reference Assembly set to Build, ccrewrite is erroring while trying to access assemblies that are referenced indirectly by assemblies that are referenced directly. These indirect assemblies are not needed to build the solution, so I'm wondering why they're required by Code Contracts? Also, is there a way to work around this problem without having to provide all runtime dependencies as part of the build?
I assume ccrewrite is trying to walk the dependency chain to analyze it for pre/postconditions, etc.. If the assemblies are referenced by assemblies which you in turn reference, then they would be required for your program to run, so ccrewrite is just performing normal analysis before you actually run the program.
That's based on using JML; I've only just started looking at the .NET Code Contracts myself. But I believe both tools operate on roughly the same principles.
The rewriter looks into method bodies of referenced assemblies in order to extract contracts (the C# compiler never does that). As a result, the rewriter often chases more dependencies than C# which is the problem you ran into.
There are two ways to address this.
add extra paths to directories where the desired libraries can be found (in the contract library paths options). This it the preferred method
As a last resort, you can add the option -ignoreMetadataErrors to the runtime contract options. Note that this is dangerous. In the case that the rewriter truly needs some aspect of the referenced code in order to create proper IL, you might end up with incorrect IL. To guard against this, use peverify on the resulting bits.
Hope this helps.

include assemblies via code? C#

In msvc i can write
#pragma comment(lib, "my.lib");
which includes my.lib in the linking stage. In my solution i have 2 projects. One is a class project the other is my main. How do i include the reference dll in code instead of adding the reference in the project?
Contrary to popular belief, it is possible :-)
To statically link .NET assemblies check out ILMerge. It's a utility that can be used to merge multiple .NET assemblies into a single one. Be it an executable or a DLL.
You could create a batch script that packages your assemblies together as a post-build step.
Edit: One thing to note however is that this does not remove the need to reference the library. The reference is still needed in order to compile your code that is dependent the external types. Much like including header files under C(++). By default c# assemblies are independent, there is no linking involved. However the tool I mentioned above allows you to create a new assembly with the external dependencies included.
As far as I know, you can't. If you need to access type that are included in a non referenced assembly, you'll have to use Assembly.Load().
I'm afraid you can't.
You can dynamically load the assembly via Assembly.Load(...) but then you have use reflection to explicitly create each Type you need to use.
I don't think you can include a dll from code without adding a reference. What you can do however is to use reflection to load that assembly and use a type from that assembly.
Assembly.Load() will get you a handle on the assembly and then you should be able to iterate through the types in the assembly.
Managed code doesn't use a linker. The C/C++ equivalent of a reference assembly is the #include directive, you need that in C/C++ to allow the compiler to generate code for an external type. Exact same thing in C#, you can't use an external type unless the compiler has a definition for it. The reference assembly supplies that.
The equivalent of C/C++ linking is done at runtime in a managed program. The JIT compiler loads assemblies as needed to generate machine code.
One thing you can do in a C# program that you can't do in a C/C++ program is using Reflection. It allows you to invoke a constructor and call a type's methods with type and method names as strings. Start that ball rolling with Assembly.GetType() and the methods of the Type class. However, consider a plug-in model with, say, the System.AddIn namespace first.
If you want to load an assembly at runtime, you can use Assembly.LoadFrom(filePath). But that way you are not referencing the assembly, and you can't use strong typing.
For example, you can have different plugins implementing a known interface (the one which is in a separate, referenced assembly), and have them all placed in a folder. Then you can check the folder and load all implementing classes at runtime (like in this example).

Can a referenced DLL be loaded even if it's not called?

Env.: .NET / VS2008
Hi All,
My app uses a 3rd party DLL assembly separately installed on some systems (clearly identified) but not all of them.
Which means that on some systems, the DLL is not there hence must not be called. To solve this, I have 2 versions of the app (using 2 configurations) for the 2 use cases. In one of them, all calls to the DLL are #if'ed out.
Since there are no calls to the DLL compiled at all in the app(they're #if'ed out), is it safe to assume that the app won't try to load the DLL even though it is referenced?
Or should I also exclude the reference?
Note: Asked in reaction to womp's comment in this question.
TIA,
IIRC, the C# compiler will omit references to dll's that are never actually used in the code. So if all code is inside #ifs, the reference to the dll will not be there in your compiled app, and the dll will never be loaded.
You can check this using Reflector, by the way. Just drag & drop your compiled app into Reflector, and look at the References node. ILDASM also provides this feature, I think.
Caveat: DllImports and dynamic type loading (e.g., Type.GetType("type,dll")) will dynamically load dlls without the C# compiler knowing or caring. But again, if inside the proper #ifs, nothing will be loaded.
I would exclude it. It might load it no matter what and if you have a type reference, then that also could cause a problem.
Why not load the the assembly dynamically if needed/available? And then if its gets added at a later date you can just make use of it? You'll only need one version of your app also.
You are safe with a reference but without the actual DLL if you never (obviously) instantiate and referenced class AND never refer to the Class in any instantiated or referenced object.
Typically your DLL will be loaded the first time the Class Constructor of a referenced Class is run.
HTH
Jan

Lingering assembly dependency in C# .NET

My C# project - we'll call it the SuperUI - used to make use of a class from an external assembly. Now it doesn't, but the compiler won't let me build the project without the assembly reference in place. Let me elaborate.
This project used to throw and catch a custom exception class - the SuperException - which was derived from the standard System.Exception and lived in a separate, precompiled assembly, SuperAssembly.DLL, which I referenced.
Eventually, I decided this was a pointless exercise and replaced all SuperExceptions with a System.SuitableStandardException in each case. I removed the reference to SuperException.DLL, but am now met with the following on trying to compile the project:
The type 'SuperException' is defined in an assembly that is not referenced. You must add a reference to assembly 'SuperException, Version=1.1.0.0 (...)'
The source file referenced by the error doesn't seem relevant; it's the project namespace that gets highlighted in the IDE.
Now, here's the thing:
All uses of SuperException have been eliminated from the project's code.
Compared to another project that compiles fine without a reference to SuperException.DLL, I only reference one more assembly - and that references nothing that my project doesn't reference itself. While it's possible that any of these dependencies could throw SuperExceptions, I'm only catching the base Exception class and in any case... the other project builds fine!
I've done Visual Studio's "Clean Solution" and cleared everything out by hand, many times.
It's not the end of the world to include this reference, I just don't see why it's necessary any more. Nrrrgg. Any pointers welcome!
It's likely a transitive reference, where some type method call returns an instance of SuperException boxed ("downcast") as e.g. Exception, but from inspecting the code in the transitively included code, i.e. code from your external method calls, the compiler knows that you need to be able to have information about that type at some point.
Resharper would tell you where it's the case that you need to add a reference, and you could use Lütz Roeder's aka RedGate's Reflector to scan compiled IL for a reference to this type in two ways: 1) use the search-facility, 2) open each public type you're using and for that one which requires the "ghost" assembly, it will ask you to specify its location.
This most often happends to me when I reference Castle.Windsor but not Castle.MicroKernel. :p
Exit Visual Studio
Delete the bin and obj Folders in your solution directory
Restart and see what happens
I agree with the other comments here.. There is a reference, in plain text somewhere !
I have had similar problems in the past where searching through the project files returned nothing, turns out it was in some other file that wasn't automatically picked up in the search.
I don't think that creating a new project is the solution here.. You need to be positive that NONE of the references in your dependency tree use SuperException.. NONE
I have never experienced this to the point where I have needed to literally wipe the project, I have always found the reference somewhere. Ensure you are searching every file.
EDIT:
Just a point to add, if the location pointed to by the error seems random, that can often mean there is a mismatch between the compiled source and the source code file.. Is this a ASP.NET application? I have had it before where the compiled DLL's haven't been replaced on a rebuild in the ASP.NET temp folder causing things to get.. Interesting when debugging :)
I don't think this is a code issue. What I can see happening is that one of your existing references probably rely on that type in their own types which you are probably creating in your application.
If that is the case you do need that reference even if you don't explicitly use the type and even though the other referenced assembly has its own reference. You sometimes get that issue with 3rd party components which need references to types that you haven't referenced. The compiler is obviously seeing something in one of your existing referenced assemblies and is expecting you to referenced the dependent one.
Since it's a compiler error, there must be a reference or use of SuperException somewhere in the project.
Do a find/replace in the entire project or solution for that type and remove every reference (it's possible you already did this).
If you reference any types that inherits from SuperException (even if the type defined in another assembly), you need a reference to the assembly that SuperException is defined in.
Take the line that the compiler is showing the error on and start tracing the inheritance tree of the objects used on that line, you might find the source of it that way.
Thanks for your answers so far. I've tried every suggestion (except one) to no avail.
The suggestion I haven't tried is to create a new project and add all my stuff to it, the thought of which really tests my will to live. ;) I may try this tomorrow if I can be bothered. Thanks again.
There is really nothing very mysterious about VS projects nowadays - it's all text files, etc. SOMETHING must reference that class/dll, and that something must be part of your project.
Have you really grep'd or findstr'd the whole solution tree, every single file, for a reference to that exception?
This sounds pretty strange. Here's what I would check next:
Check that there's nothing lingering in your Properties/AssemblyInfo.cs file.
Check that there's nothing lingering in your SuperUI.csproj file.
Delete all references and re-add them.
Try creating a new project, and adding all your classes to it.
grep your project folder. It could be a hidden reference in your project, or a project that your project references. Cleanse with Notepad if needed.
If you reference any types that inherits from SuperException (even if the type defined in another assembly), you need a reference to the assembly that SuperException is defined in.
Seconded on that.
You might not be referencing SuperException, but you might be referencing SpecializedSuperException, which is derived from, or somehow otherwise uses SuperException - your grep of the project for SuperException won't be catching it though.
Try have a hack with the trial of NDepend
This is where tools like Resharper really pay off -- a simple Find Usages usually tells me of such "ghost dependencies" several times.
Maybe you could go to your definition of the SuperException class and try to Find All References(). You might also want to investigate if the assembly SuperException is has a circular dependency on your main assembly (e.g., main assembly depends on exception assembly depends on main assembly...).
I’ve had a very similar assembly reference issue that was happening when my C# library had a dependent C++/CLI assembly.
The problem that was I was inheriting a public class from that C++/CLI assembly in my C# assembly library. That meant that the inheritance chain was spanning across multiple assemblies.
I was hoping that any client would be smart enough to indirectly load the C++/CLI assembly any time the C# library needed it, but that was not the case even at compile time.
I got rid of this problem by breaking the inheritance between the classes that were spanning across those two assembly libraries and using aggregation instead.
My client was finally happy and did not require the C++/CLI assembly as a dependency anymore.
In your word you would probably have to make sure that SuitableStandardException does not inherit from SuperException in order to eliminate the SuperException.DLL as a reference.
Use encapsulation instead of inheritance and create a SuperException data member in your new SuitableStandardException.
If that does not solve it, you might have more classes spanning inheritance across some assemblies, in your case SuperAssembly.DLL and superException.dll.
If you can't find all of them try this trick:
Make all your public members and classes in SuperAssembly.DLL internal.
In the SuperAssembly.DLL make friends with SuperException.DLL:
[assembly:InternalsVisibleTo("SuperException, PublicKey=0024000004800000....)]
Make sure that they build and remove the SuperAssembly.DLL reference from any client that already references SuperException.DLL.
grep -R SuperException * in the base of your project (get grep from somewhere first) just to be sure.

Categories

Resources