【问题标题】:C# How to generate an object implementing different interfaces dynamically at runtime?C#如何在运行时动态生成实现不同接口的对象?
【发布时间】:2009-11-03 10:04:30
【问题描述】:

我正在研究如何解决问题,但我什至不确定这在 C# 和 .NET 3.5 中是否可行:

假设我的接口数量有限,每个接口都描述了一组特定的、不相关的方法。现在我有许多现实世界的设备,每个设备都可以实现这些接口的一个子集。

在使用这些设备设置通讯时,它们会告诉我它们具有哪些功能。我现在想创建一个实现接口的对象(每个接口都类似于设备的一种功能),以便在我的应用程序架构的更高层次上:

  • 针对上述接口编写代码
  • 测试生成的对象是否实现了某个接口以查看是否支持某些操作

我完全不确定使用哪种方法来解决这个问题。欢迎任何 cmets 或方法!

【问题讨论】:

  • 首先感谢大家的cmets和建议。非常感谢!好的,我想我应该详细说明一下我面临的问题。我有一定数量的能力,例如CanMakeCoffe、CanCleanKitchen 等。大多数设备都会实现一些功能,例如可以制作咖啡。我想避免的是在源代码类中为这些设备定义某处,如在 CDeviceOne 中:ICanMakeCoffee、ICanCleanKitchen CDeviceTwo:ICanMakeCoffee
  • 我宁愿让设备在他们连接时告诉我他们能做什么,然后我会创建一个类似于他们能力的对象。这有意义吗?

标签: c# dynamic interface


【解决方案1】:

使用mocking framework,例如MoqRhinoMocksTypeMock Isolator

如果你想做一些较低级别的事情,像Castle DynamicProxy 这样的事情可能对你来说是一个很好的方向。

【讨论】:

  • 搜索duck typing也可能产生结果。
  • @leppie:非常好的观点。 @Timo:如果您使用诸如 IronPython 或 IronRuby 之类的动态语言(或 C# 4 中的动态相关内容),您可能能够实现一些有用的东西(尽管您不会使用实际的 interface 定义和 is 或 @987654328 @在实现中
  • @leppie:感谢您的建议。我已经看过鸭子打字,但我不确定它是否能帮助我解决这个问题。反正我再看看! @Ruben:感谢您对 DynamicProxy 的指点。最有趣的!我也会仔细看看那里。
【解决方案2】:

【讨论】:

  • 确实很有趣。我特别喜欢创建 mixin 的想法。我只是有点犹豫是否将这种框架用于生产代码......我将不得不查看许可证。无论如何,谢谢!
  • 它被授权为 LGPL。你应该感谢菲利普,而不是我:)
【解决方案3】:

也许你不需要让它变得如此“动态”。

您检查过Abstract Factory 模式吗?看来基本上你需要的是基于设备type为你的每个接口创建一个具体的实现。

你不需要一个类实现很多接口,当你的代码请求特定接口时有适当的实现就足够了。

抽象工厂的每个具体实现都可以根据您的设备类型生成多个接口实现。

例子:

 public interface IDeviceFactory
 {
      ISomething GetSomeInterface();
      ISomethingElse GetSomeOtherInterface();
 }

然后为每个设备实现特定的工厂:

public class SimpleDeviceFactory : IDeviceFactory
{
     public virtual ISomething GetSomeInterface()
     { return Something.Empty; }

     public virtual ISomethingElse GetSomeOtherInterface()
     { return new SomeSimpleConreteImplementation(); }
}

或者也许:

public class ComplexDeviceFactory : IDeviceFactory
{
     public virtual ISomething GetSomeInterface()
     { return new ComplexStuff(); }

     public virtual ISomethingElse GetSomeOtherInterface()
     { return new EvenMoreComplexStuff(); }
}

然后,最后,为您的设备创建正确的工厂:

public class DeviceFactory
{
     public static IDeviceFactory CreateForDevice(IDevice device)
     {
          DeviceType type = device.Type; // or something like this
          switch (type)
          {
              case DeviceType.Simple: 
                 return new SimpleDeviceFactory();

              case DeviceType.Complex: 
                 return new ComplexDeviceFactory();

              default:
                 throw new NotImplementedException();
          }
     }
}

请注意,我还将 IDeviceFactory 方法实现标记为virtual,以便您可以轻松地重用或覆盖特定设备的特定接口。

【讨论】:

  • 感谢 Groo,这确实是解决问题的直接方法!正如我在对原始问题的评论中所说,我想避免使代码“以设备为中心”(为每个可能的设备创建类),而是根据设备的反馈创建一个对象(它能够做)。
【解决方案4】:

这是可能的,只是不容易。您需要创建一个基本上是源文件的字符串,然后创建并使用 CSharpCodeProvider,然后您可以订购它来编译您的代码。如果可行,您可以通过反射手动访问您创建的对象。

对于有兴趣的,我前一阵子做过,细节有点模糊。

【讨论】:

  • 将 il 代码发送到内存中的动态程序集可能很容易。然而,一个模拟框架可以更容易/用更少的代码做到这一点。 ;)
【解决方案5】:

.NET 4 可能会更容易,您可以使用已经提到的框架之一或使用 System.Reflection 路线。您会在 Internet 上找到大量示例。

我过去都做过。滚动我自己的 il.Emit 东西并使用框架(在我的例子中是 Spring.NET)。对于无关紧要的东西,请使用其中一个框架。

【讨论】:

    【解决方案6】:

    您也可以尝试使用Re-mix 项目。该项目的主要功能之一是创建mixins,它允许您将具有实现和状态的接口添加到其他类。看看这个例子:

    using Remotion.Mixins;
    using Remotion.TypePipe;
    //...
    
    public interface ITargetInterface
    {
        void DoSomething();
    }
    // . . .
    public class TargetImplementation : ITargetInterface
    {
        public void DoSomething()
        {
            Console.WriteLine("ITargetInterface.DoSomething()");
        }
    }
    // . . .
    public interface IMixinInterfaceA
    {
        void MethodA();
    }
    // . . .
    public class MixinImplementationA : IMixinInterfaceA
    {
        public void MethodA()
        {
            Console.WriteLine("IMixinInterfaceA.MethodA()");
        }
    }
    // . . .
    public interface IMixinInterfaceB
    {
        void MethodB(int parameter);
    }
    
    // . . .
    public class MixinImplementationB : IMixinInterfaceB
    {
        public void MethodB(int parameter)
        {
            Console.WriteLine("IMixinInterfaceB.MethodB({0})", parameter);
        }
    }
    

    然后你可以合并这些类型来创建一个 mixin:

    var config = MixinConfiguration.BuildFromActive()
                .ForClass<TargetImplementation>()
                .AddMixin<MixinImplementationA>()
                .AddMixin<MixinImplementationB>()
                .BuildConfiguration();
    MixinConfiguration.SetActiveConfiguration(config);
    

    不幸的是,您不能简单地在 TargetImplementation 上调用 new 并期待一个 mixin。相反,您必须要求 Re-mix 创建一个 TargetImplementation 实例,以便它可以根据您的规范构建一个新类型并实例化它。当它被要求提供TargetImplementation 的实例时,它将返回一个包含所有接口和类组合的mixin。

    ITargetInterface target = ObjectFactory.Create<TargetImplementation>(ParamList.Empty);
    
    target.DoSomething();
    
    var targetAsMixinA = target as IMixinInterfaceA;
    if (targetAsMixinA != null)
    {
       targetAsMixinA.MethodA();
    }
    
    var targetAsMixinB = target as IMixinInterfaceB;
    if (targetAsMixinB != null)
    {
        targetAsMixinB.MethodB(30);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 2014-04-11
      • 2021-08-14
      • 2011-03-30
      • 1970-01-01
      相关资源
      最近更新 更多