Ed Landau
Ed Landau

Reputation: 998

Pragmatically detect if if I forget to include an assembly

SEE EDITS AT THE END.

I have an app that requires to user to install a 3rd party application for mine to run. I'd like to make my application provide a warning to the user if they have forgotten to install this 3rd party app instead of just quitting as a result of trying to access a missing assembly.

In C#, I'd like to check if an assembly is included.

I thought I could use:

object.ReferenceEquals(Oject, null)

But but object.ReferenceEquals does not like to take Type as an input.

I tried:

    var type = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
        from type2 in assembly.GetTypes()
        where type2.Name == "Oject"
        select type2);
    if (type == null) {...}

But Visual Studio shows me that type can never be null.

So: Is there a simple way I can detect if I forgot to include an assembly before I access it (and the app just quits with no warning or message telling the user WHY it quit)?

I thought I could use

try
{
    types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
    types = ex.Types.Where(p => p != null).ToArray();
}

from: Missing types using reflection on DLL but I'm doing this check from Program.cs that is a static class.

EDIT: It turns out that I have the referenced assemblies but that these assemblies may not have the correct logic installed. So the references came along with all the binaries but since the 3rd party app was not installed, those binaries went bonkers when they could not reach their intended targets and it is those binaries that seem to be failings.

So... I still have this issue but it may explain I cannot "Catch" ??

Upvotes: 2

Views: 52

Answers (1)

user6656930
user6656930

Reputation:

An interesting fact about type loading in .NET. A type is loaded upon entering a method that uses it. An assembly is loaded when the first type is loaded. So, example code below (assuming "SomeType" is a type in the assembly you are looking for)

So by this logic you can have:

static void Main() {
    if (CanLoad()) {
        DoStuff();
    } else {
        Console.WriteLine("Some error message");
    }
}

static void DoStuff() {
    // Ok to reference SomeType here
}

private static bool CanLoad() {
    try {
        TryLoad();
        return true;
    } catch {
        return false;
    }
}

private static void TryLoad() {
    Type t = typeof(SomeType);
}

With this code, what happens is this. Main calls CanLoad normally. CanLoad doesn't need any fancy type, so it happily starts up, and then attempts to call TryLoad. TryLoad, however, has a reference to "SomeType", so when the compiler attempts to enter that method, before executing any part of it, it attempts to load the assembly containing "SomeType". If this fails, the method throws a FileNotFoundException trying lo load it. We catch that in CanLoad and return false.

It's very important that neither "Main" nor "CanLoad" have any references to that assembly at all (even after the check), or they will crash before the check (remember, the loads are done when entering a method, not on reaching the line), but "DoStuff" can reference whatever it wants.

Upvotes: 1

Related Questions