【问题标题】:creating an instance of a class that is in separate project in C#在 C# 中创建位于单独项目中的类的实例
【发布时间】:2017-03-14 18:05:37
【问题描述】:

我有两个课程“菜单”和“膳食”。 Menu 需要根据 Run-time 中的路径创建 Meals 的实例。例如我有这样的路径 C:\Users\devmachine\Documents\Visual Studio 2017\Projects\MealsLibrary\MealsLibrary\Meals.cs

菜单类在不同的解决方案中,也在不同的硬盘位置。

所以,到目前为止,我正在尝试使用 Reflection.Assembly.LoadFrom 但我没有成功,它告诉我需要一个程序集清单。

那么,如何在单独的解决方案中创建一个类的实例?

【问题讨论】:

  • 我的工作要求是这个类一直在变化,因此不值得添加它作为参考。
  • 如果更改的类在您管理的另一个解决方案或项目中,您当然需要参考。当您更改该类时,重新构建和引用它的程序集将在构建时自动获取最新的 .dll
  • 是“单独的解决方案” = 两个独立的团队维护自己的程序集,您希望互操作吗?那么两个团队应该就不会一直更改的接口达成一致,您可以编写该接口的模拟实现以进行开发和测试,并在生产中使用运行时绑定。
  • 我向我们的软件架构师提出了同样的声明,但他希望我如何编写这个应用程序。没有引用,都在运行时。

标签: c# visual-studio reflection .net-assembly


【解决方案1】:

为了在 AssemblyB 中从 AssemblyA 中实例化类型 ClassB,其中 AssemblyB 不是被引用的程序集(但加载了 Assembly.LoadNnn,您可以执行以下操作:

  1. 通过Assembly.LoadNnn 重载之一加载程序集
  2. 扫描已加载程序集的DefinedTypes以检测类型
  3. 使用Activator.CreateInstanceNnn 实例化类型

这里有一些代码可以为你做到这一点:

    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);
            }
        }
    }

但是,这实际上使用起来非常不方便,因此您最好使用两个程序集通用的接口。有了它,您可以将您的 ClassB 转换为例如IClassB 并访问其属性而无需回退到反射。而不是使用Assembly.LoadFromActivator.CreateInstanceFrom 我会考虑使用StructureMap 这样你就可以扫描你的程序集并从中获取一个实例(尽管它可能被认为是一个反模式,但不会比Activator 本身造成更大的伤害) .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    • 2021-11-14
    • 2023-03-14
    • 2015-11-17
    相关资源
    最近更新 更多