【问题标题】:can a C# 'dynamic' variable refer to a static type?C#“动态”变量可以引用静态类型吗?
【发布时间】:2015-04-03 04:50:30
【问题描述】:

我正在使用通过静态类提供服务的第 3 方程序集:

Foo.Bar.StaticLibraryClass.Start();
var x = Foo.Bar.StaticLibraryClass.GetSomeStuff();
Foo.Bar.StaticLibraryClass.Stop();

如果类不是静态的,我可以通过动态类型变量使用它的实例:

dynamic lib = new Foo.Bar.NotStaticLibraryClass();
lib.Start();
var x = lib.GetSomeStuff();
lib.Stop();

不幸的是,这个类是静态的。有没有我可以写的等价物让我以同样的方式工作?

dynamic lib = /* ??????? */
lib.Start();
var x = lib.GetSomeStuff();
lib.Stop();

(为什么我想要使用dynamic 变量来访问一个完美的.NET 类型?实际上有多个版本的库DLL,我必须识别并加载合适的一个在运行时。不同的 DLL 公开相同的类型和方法名称,但它们确实继承自任何公共接口。因此,如果我能找到一种使用动态类型的方法,它将使我免于编写大量繁琐的反射代码来使用DLL 的方法。)

【问题讨论】:

    标签: dynamic c#-4.0


    【解决方案1】:

    抱歉,C# dynamic 不直接支持这种用法。为了在 C# 中调用类方法,您必须直接在源代码中命名类型。为此,您必须引用程序集。动态不会改变这一点。

    动态确实在必要时(例如当您有动态参数时)分派给类方法,但即使在这些情况下,上述限制仍然存在。

    如果目标类型提供了一个可以放入动态变量的实例,那么就可以了。如果您提供了这样的实例,那就没问题了。或者,如果您对动态感兴趣,您可以编写自己的 IDynamicMetaObjectProvider,在给定 System.Type 的情况下动态包装这些类方法。如果您至少想了解 DLR,那将是一个很有启发性的项目。

    【讨论】:

      【解决方案2】:

      c#/vb.net 等是静态类型语言。因此,如果您的类型没有 Start 方法,则代码将无法编译。

      dynamic 关键字在静态语言和动态语言之间架起了一座桥梁。
      即是否存在方法,在动态语言的情况下在运行时检查。

      在您的示例中,StartStop、'GetSomeStuffmethod exists and your code is aware of it. Moreover,dynamic` 与动态加载程序集无关。

      我认为您需要某种插件/提供者类型的模型,您将拥有一个基本接口,您的实现类将确认该接口。

      例如

      interface IService
      {
         void Start();
         void Stop();
         int GetSomeStuff();
      }
      

      并且实现类(将在单独的程序集中)将确认此接口,您将在代码中动态加载并强制转换为此接口 (IService)。

      依赖注入/控制反转是我想到的一个概念,我认为它应该满足您的需求。

      【讨论】:

      • 您是正确的,dynamic 关键字的主要用途是从静态语言到动态语言或到 COM 对象的桥接。然而,它不限于该用途。例如,我可以编写以下代码并且它工作正常:dynamic st1 = "test"; dynamic st2 = st1.ToUpper(); string st3 = st2.ToString(); 我碰巧有一个用例,我需要加载不同版本的程序集,我不能要求任何通用接口,即使它们在内部具有相似的类型名称.使用dynamic 可以让我避免大量繁琐的手动反射。
      • @Eric: dynamic 对于已经加载的类型很有用(我猜)。因此,必须手动加载程序集。在这种情况下,创建该类型的实例(使用Activator.CreateInstance)并将其分配给dynamic 变量应该会有所帮助。
      【解决方案3】:

      使用dynamic的魔力:

      using System;
      using System.Dynamic;
      using System.Reflection;
      
      public class StaticInvoker : DynamicObject
      {
          readonly BindingFlags flags;
          readonly Type type;
      
          public StaticInvoker(Type staticType) : this(staticType, false)
          {
      
          }
      
          public StaticInvoker(Type staticType, bool nonPublic)
          {
              type = staticType;
              flags = BindingFlags.Static | BindingFlags.Public | (nonPublic ? BindingFlags.NonPublic : 0);
          }
      
          public override bool TryGetMember(GetMemberBinder binder, out object result)
          {
              try{
                  result = type.InvokeMember(binder.Name, flags | BindingFlags.GetField | BindingFlags.GetProperty, null, null, null);
                  return true;
              }catch(TargetInvocationException e)
              {
                  throw e.InnerException;
              }catch(MissingMemberException)
              {
                  result = null;
                  return false;
              }
          }
      
          public override bool TrySetMember(SetMemberBinder binder, object value)
          {
              try{
                  type.InvokeMember(binder.Name, flags | BindingFlags.SetField | BindingFlags.SetProperty, null, null, new[]{value});
                  return true;
              }catch(TargetInvocationException e)
              {
                  throw e.InnerException;
              }catch(MissingMemberException)
              {
                  return false;
              }
          }
      
          public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
          {
              try{
                  result = type.InvokeMember(binder.Name, flags | BindingFlags.InvokeMethod, null, null, args);
                  return true;
              }catch(TargetInvocationException e)
              {
                  throw e.InnerException;
              }catch(MissingMemberException)
              {
                  result = null;
                  return false;
              }
          }
      }
      

       

      dynamic lib = new StaticInvoker(typeof(Foo.Bar.StaticLibraryClass));
      

      支持所有基本操作。

      【讨论】:

        猜你喜欢
        • 2010-09-09
        • 2013-07-05
        • 2021-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-14
        相关资源
        最近更新 更多