-2

I have two classes 'Menu' and 'Meals'. Menu needs to create an instance of Meals based on a path in Run-time. For example I have path such as C:\Users\devmachine\Documents\Visual Studio 2017\Projects\MealsLibrary\MealsLibrary\Meals.cs

Menu class is in a different solution and also in a different hard drive location.

so, far I'm trying to use Reflection.Assembly.LoadFrom but I have not success it's telling me that expects a assembly manifest.

So, How to create an instance of a class that is in a separate solution?

Ronald Rink 'd-fens'
  • 1,289
  • 1
  • 10
  • 27
Victor A Chavez
  • 181
  • 1
  • 19
  • 3
    Possible duplicate of [How to add a .dll reference to a project in Visual Studio](http://stackoverflow.com/questions/12992286/how-to-add-a-dll-reference-to-a-project-in-visual-studio) – BCartolo Mar 14 '17 at 18:07
  • The requirement from my work is that this class is changing all the time and therefore is not worth to add it as a reference. – Victor A Chavez Mar 14 '17 at 18:11
  • If the class that changes is in another solution or project you manage, you certainly want a reference. When you change that class, rebuild and the assemblies that reference it will automatically get the latest .dll when they build – maccettura Mar 14 '17 at 18:14
  • 1
    is "separate solution" = two independent teams maintain their own assemblies, and you are expected to interoperate? then the two teams should agree on an interface that does not change all the time, and you could write a mock implementation of that interface to develop and test against, and use runtime binding in production. – Cee McSharpface Mar 14 '17 at 18:16
  • I have argued the same statement to our software architect but that how he wants me to code this application. No references, all in runtime. – Victor A Chavez Mar 14 '17 at 18:16
  • Building an assembly at the runtime seems like a really bad way to do it. You should just have dependency on the assembly that has Menu in it and deploy it whenever you need. – CrudaLilium Mar 14 '17 at 18:17
  • I'm guessing there's a reason the architect wants to do it that way. You need to find that out and tell us. – Dour High Arch Mar 14 '17 at 19:18
  • can you please show your code where you call `Reflection.Assembly.LoadFrom` along with the exception that is raised? – Ronald Rink 'd-fens' Mar 15 '17 at 11:54

1 Answers1

1

In order to instantiate a type ClassB inside AssemblyB from AssemblyA where AssemblyB is NOT a referenced assembly (but loaded with Assembly.LoadNnn you can do the following:

  1. Load the Assembly via one of the Assembly.LoadNnn overloads
  2. Scan DefinedTypes of the loaded assembly to detect the type
  3. Use Activator.CreateInstanceNnn to instantiate the type

Here is some code that would do that for you:

    using System;
    using System.Reflection;
    using System.Diagnostics.Contracts;

    // this is AssemblyB
    // residing at C:\TEMP\AssemblyB.dll
    namespace Com.Example.SO12188029.AssemblyB
    {
        public class ClassB
        {
            public string Property { get; set; } = "tralala";
        }
    }

    // this is AssemblyA
    // residing at C:\SomeWhereElse\AssemblyA.dll
    namespace Com.Example.SO12188029.AssemblyA
    {
        public class ClassA
        {
            private const string assemblyBPathAndFileName = @"C:\TEMP\AssemblyB.dll";
            private const string typeFromAssemblyBToBeInstantiated = @"Com.Example.SO12188029.AssemblyB.ClassB";

            public static void Main(string[] args)
            {
                // try to load assembly
                var assembly = Assembly.LoadFrom(assemblyBPathAndFileName);
                Contract.Assert(null != assembly, assemblyBPathAndFileName);

                // make sure type exists in assembly
                var type = assembly.DefinedTypes.First(e => e.IsClass && !e.IsAbstract
                    && e.FullName == typeFromAssemblyBToBeInstantiated);
                Contract.Assert(null != type, typeFromAssemblyBToBeInstantiated);

                // try to get instance of type
                var instance = Activator.CreateInstance(assembly.ManifestModule.FullyQualifiedName, typeFromAssemblyBToBeInstantiated);

                // ... now we have an instance, but as long as you do not know what *kind* of instance this is
                // you cannot do much with it, unless - we use reflection to get access to the instance

                var propertyInfo = instance.GetType().GetProperty("Property");
                var propertyValue = propertyInfo.GetValue(instance);

                Console.WriteLine("ClassB.PropertyValue '{0}'", propertyValue);
            }
        }
    }

However, this is actually very inconvenient to use, so you better use interfaces that are common to both assembly. With that you can cast your ClassB to e.g. IClassB and access its properties without falling back to reflection. And instead of using Assembly.LoadFrom and Activator.CreateInstanceFrom I would consider using StructureMap so you can scan your assemblies and get an instance from it (though it might be considered an AntiPattern, but not doing more harm than Activator itself).

Ronald Rink 'd-fens'
  • 1,289
  • 1
  • 10
  • 27