如何将静态类包装在非静态实例对象中(动态地)
本文关键字:对象 动态 实例 静态 静态类 包装 | 更新日期: 2023-09-27 17:58:05
我有一个有趣的问题。我需要动态地包装静态类。也就是说,给我的调用者返回一个非静态实例。例如:
public object CreateInstance(string className) {
Type t = assembly.GetType(className);
if (IsStatic(t)) {
return CreateStaticWrapper(t);
} else {
return Activator.CreateInstance(t);
}
}
所以我需要的是关于如何实现CreateStaticWrapper
的指针。
注意:不幸的是,我不能使用动态对象。
那么我有什么选择呢?我不是那么热衷于学习IL世代吗?如果IL生成(Reflection.Emit,或者现在有其他方法吗?)是可行的,有人在那里有指针吗?
编辑:需要注意的是,我可以返回一个委托字典。所以我可以使用Delegate.CreateDelegate
,但我似乎不知道如何处理重载方法和泛型方法。
第2版:另一个选项是使用Emit向类型中注入一个空构造函数,还有指针吗?这在标记为静态的类型上可能吗?static关键字是否进入IL?
第3版:关于上下文,我将把它传递给一个javascript环境,请参阅:我的项目。所以我希望能够(在JavaScript中):
var fileHelper = .create('System.IO.File');
if (fileHelper.Exists(fileName)) { fileHelper.Delete(fileName); }
谢谢大家。
尝试创建一个继承自System.Dynamic.DynamicObject
的包装器类。在包装类中,使用反射来调用静态类的方法。
你需要这样的东西:
public class StaticWrapper<T> : System.Dynamic.DynamicObject
{
private static readonly Type t = typeof(T);
public static int MyProperty { get; set; }
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result)
{
try
{
result = t.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Public, null, null, args);
return true;
}
catch
{
result = null;
return false;
}
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
{
try
{
var p = t.GetProperty(binder.Name);
if (p != null)
result = p.GetValue(null, null);
else
{
var f = t.GetField(binder.Name);
if (f != null) result = f.GetValue(null);
else { result = null; return false; }
}
return true;
}
catch
{
result = null;
return false;
}
}
public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value)
{
try
{
var p = t.GetProperty(binder.Name);
if (p != null)
p.SetValue(null, value, null);
else
{
var f = t.GetField(binder.Name);
if (f != null) f.SetValue(null, value);
else return false;
}
return true;
}
catch (SystemException)
{
return false;
}
}
}
希望它能起作用。
我会说去IL生成。创建代理是一个非常简单的场景。实际上,我写了一篇关于它的博客文章:einarwh.posterous.com/patching-polymorphic-pain-at-runtime。场景不同,但解决方案几乎相同。
除了不需要将"this"引用加载到堆栈上(因为您正在进行静态方法调用)之外,您基本上可以完全按照博客文章中的方式进行操作。
好吧,我想出的解决方案如下,我阅读并研究了Einar的博客文章,他在上面发表了评论。谢谢埃纳尔。
但我想我会在这里发布我的完整代码解决方案,以防将来对某人有所帮助:
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace js.net.jish.Command
{
public class StaticTypeWrapper
{
private readonly Type staticType;
public StaticTypeWrapper(Type staticType)
{
this.staticType = staticType;
}
public object CreateWrapper()
{
string ns = staticType.Assembly.FullName;
ModuleBuilder moduleBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(ns), AssemblyBuilderAccess.Run).DefineDynamicModule(ns);
TypeBuilder wrapperBuilder = moduleBuilder.DefineType(staticType.FullName, TypeAttributes.Public, null, new Type[0]);
foreach (MethodInfo method in staticType.GetMethods().Where(mi => !mi.Name.Equals("GetType")))
{
CreateProxyMethod(wrapperBuilder, method);
}
Type wrapperType = wrapperBuilder.CreateType();
object instance = Activator.CreateInstance(wrapperType);
return instance;
}
private void CreateProxyMethod(TypeBuilder wrapperBuilder, MethodInfo method)
{
var parameters = method.GetParameters();
var methodBuilder = wrapperBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, parameters.Select(p => p.ParameterType).ToArray());
var gen = methodBuilder.GetILGenerator();
for (int i = 1; i < parameters.Length + 1; i++)
{
gen.Emit(OpCodes.Ldarg, i);
}
gen.Emit(OpCodes.Call, method);
gen.Emit(OpCodes.Ret);
}
}
}
所以,假设我们使用"Delegate.CreateDelegate"的方式。让我们看看之后我们是否能获得更多关于您其他问题的详细信息。。。让我们从开始
public static object Generate(Type t)
{
if(IsStatic(t))
{
var dictionary = new Dictionary<string, Delegate>();
foreach (var methodInfo in t.GetMethods())
{
var d = Delegate.CreateDelegate(t, methodInfo);
dictionary[methodInfo.Name] = d;
}
return dictionary;
}
return Activator.CreateInstance(t);
}
静态类是"密封的",因此不能继承。所以我不明白你说的"超负荷"是什么意思。对于泛型方法,我们需要在将methodInfo.MakeGenericMethod(...)
添加到字典之前调用它。但你需要事先知道类型,我想你不会。。。或者,你可以做一些类似的事情:
...
if (methodInfo.IsGenericMethod)
{
d = new Func<MethodInfo, Type[], Delegate>(
(method, types) =>
Delegate.CreateDelegate(
method.DeclaringType, method.MakeGenericMethod(types)));
}
dictionary[methodInfo.Name] = d;
...
这将为您提供一个接受类型数组(泛型类型参数)的委托,并从中生成一个工作委托。