我很确定我错过了一些限制或警告的地方,但这是我的情况。假设我有,我想有一个代理类,如下所示:我可以在RealProxy实例中使用反射吗?
public class MyList : MarshalByRefObject, IList<string>
{
private List<string> innerList;
public MyList(IEnumerable<string> stringList)
{
this.innerList = new List<string>(stringList);
}
// IList<string> implementation omitted for brevity.
// For the sake of this exercise, assume each method
// implementation merely passes through to the associated
// method on the innerList member variable.
}
我想创建该类的代理,这样我可以拦截方法调用与底层对象进行一些处理。下面是我的实现:
public class MyListProxy : RealProxy
{
private MyList actualList;
private MyListProxy(Type typeToProxy, IEnumerable<string> stringList)
: base(typeToProxy)
{
this.actualList = new MyList(stringList);
}
public static object CreateProxy(IEnumerable<string> stringList)
{
MyListProxy listProxy = new MyListProxy(typeof(MyList), stringList);
object foo = listProxy.GetTransparentProxy();
return foo;
}
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage callMsg = msg as IMethodCallMessage;
MethodInfo proxiedMethod = callMsg.MethodBase as MethodInfo;
return new ReturnMessage(proxiedMethod.Invoke(actualList, callMsg.Args), null, 0, callMsg.LogicalCallContext, callMsg);
}
}
最后,我有消耗代理的类的类,我设置为通过反射MyList
成员的值。
public class ListConsumer
{
public MyList MyList { get; protected set; }
public ListConsumer()
{
object listProxy = MyListProxy.CreateProxy(new List<string>() { "foo", "bar", "baz", "qux" });
PropertyInfo myListPropInfo = this.GetType().GetProperty("MyList");
myListPropInfo.SetValue(this, listProxy);
}
}
现在,如果我尝试使用反射来访问代理对象,我遇到了问题。下面是一个例子:
class Program
{
static void Main(string[] args)
{
ListConsumer listConsumer = new ListConsumer();
// These calls merely illustrate that the property can be
// properly accessed and methods called through the created
// proxy without issue.
Console.WriteLine("List contains {0} items", listConsumer.MyList.Count);
Console.WriteLine("List contents:");
foreach(string stringValue in listConsumer.MyList)
{
Console.WriteLine(stringValue);
}
Type listType = listConsumer.MyList.GetType();
foreach (Type interfaceType in listType.GetInterfaces())
{
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
// Attempting to get the value of the Count property via
// reflection throws an exception.
Console.WriteLine("Checking interface {0}", interfaceType.Name);
System.Reflection.PropertyInfo propInfo = interfaceType.GetProperty("Count");
int count = (int)propInfo.GetValue(listConsumer.MyList, null);
}
else
{
Console.WriteLine("Skipping interface {0}", interfaceType.Name);
}
}
Console.ReadLine();
}
}
尝试调用GetValue
经由反射Count
属性引发以下例外:
类型“System.Reflection.TargetException”的异常出现在 mscorlib.dll中但未在用户代码中处理
附加信息:对象与目标类型不匹配。
当试图获取Count
属性的值,显然框架调用分解成System.Runtime.InteropServices.WindowsRuntime.IVector
调用get_Size
方法。我不理解这个调用如何在代理的基础对象(实际列表)上失败以实现这一点。如果我不使用对象的代理,通过反射获取属性值可以正常工作。我究竟做错了什么?我甚至可以做我想要完成的事情?
编辑: A bug has been opened关于Microsoft Connect站点上的此问题。
注意这个实现不是闲置的猜测。 [MbUnit的'Assert.Count'方法](https://github.com/Gallio/mbunit-v3/blob/master/src/MbUnit/MbUnit/Framework/Assert.Count.cs)为某些集合执行此操作。如果集合对象是代理,则会调用'Assert.Count'。 – JimEvans
是否有可能使MyListProxy.CreateProxy通用,以便返回实型而不是类型对象?对于测试:如果在main'interfaceType.GetProperty(“Count”)'中的这个调用改变为'((MyList)interfaceType).GetProperty(“Count”)'然后调用'Count'work? – pasty
这里有类似的问题 - 使用Invoke()似乎会导致编组,导致执行落入此VectorToCollectionAdapter,然后Bar栏中出现消息“Object与目标类型不匹配”。 (因为IVector不是ICollection)。我认为这是一个错误。 – fusi