我正在使用通过静态类提供服务的第三方程序集:
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的方法。)
答案 0 :(得分:0)
c#/ vb.net等是静态类型语言。因此,如果您的类型没有Start
方法,则代码将无法编译。
dynamic
关键字填补了静态语言和动态语言之间的空白
即,在动态语言的情况下,在运行时检查方法是否存在。
在您的示例中,Start
,Stop
,'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));
支持所有基本操作。