我很確定我錯過了一些限制或警告的地方,但這是我的情況。假設我有,我想有一個代理類,如下所示:我可以在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