C#'dynamic'变量可以引用静态类型吗?

时间:2010-06-23 14:35:29

标签: dynamic c#-4.0

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

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的方法。)

3 个答案:

答案 0 :(得分:0)

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

dynamic关键字填补了静态语言和动态语言之间的空白 即,在动态语言的情况下,在运行时检查方法是否存在。

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

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

e.g。

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

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

依赖注入/控制反转是一个我想到的概念,我认为它应该服务于你正在寻找的东西。

答案 1 :(得分:0)

抱歉,C#dynamic不直接支持此用法。要在C#中调用类方法,必须直接在源代码中命名类型。要做到这一点,你必须参考组件。动态不会改变这一点。

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

如果目标类型提供了一个可以放在动态变量中的实例,那么你就可以了。如果您提供了这样的实例,那就没事了。或者,如果您将心脏设置为动态,则可以编写自己的IDynamicMetaObjectProvider,在给定System.Type的情况下动态包装这些类方法。如果你想了解DLR,那将是一个有益的项目,至少。

答案 2 :(得分:0)

使用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));

支持所有基本操作。