Sono abbastanza sicuro che mi manca qualche vincolo o avvertenza da qualche parte, ma qui è la mia situazione. Si supponga che ho una classe che voglio avere un proxy per, come il seguente:È possibile utilizzare la riflessione con istanze 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.
}
voglio creare un proxy per quella classe, in modo che possa intercettare le chiamate di metodo e di eseguire alcune elaborazioni sull'oggetto sottostante . Qui è la mia realizzazione:
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);
}
}
Infine, ho una classe che consuma la classe Proxied, e ho impostato il valore del membro MyList
attraverso la riflessione.
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);
}
}
Ora, se provo a utilizzare il reflection per accedere all'oggetto proxy, mi imbatto in problemi. Ecco un esempio:
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();
}
}
tentativo di chiamare GetValue
dell'immobile Count
tramite riflessione genera la seguente eccezione:
Un'eccezione di tipo 'System.Reflection.TargetException' verificata in mscorlib.dll ma non è stato gestito nel codice utente
Ulteriori informazioni: L'oggetto non corrisponde al tipo di destinazione.
Quando si tenta di ottenere il valore della proprietà Count
, a quanto pare il quadro sta chiamando giù in System.Runtime.InteropServices.WindowsRuntime.IVector
per chiamare il metodo get_Size
. Non sto capendo come questa chiamata fallisce sull'oggetto sottostante del proxy (la lista vera e propria) per farlo accadere. Se non sto usando un proxy dell'oggetto, ottenere il valore della proprietà funziona bene tramite riflessione. Che cosa sto facendo di sbagliato? Posso fare anche quello che sto cercando di realizzare?
Modifica: A bug has been opened relativo a questo problema nel sito Microsoft Connect.
Nota questa implementazione non è speculazione inattiva. [Il metodo 'Assert.Count' di MbUnit] (https://github.com/Gallio/mbunit-v3/blob/master/src/MbUnit/MbUnit/Framework/Assert.Count.cs) lo fa per alcune raccolte. Se l'oggetto collection è un proxy, la chiamata a 'Assert.Count' genera. – JimEvans
È possibile rendere generico 'MyListProxy.CreateProxy', in modo che restituisca il tipo reale e non l'oggetto di tipo? Per il test: se questa chiamata nel principale 'interfaceType.GetProperty (" Count ")' è cambiata in '((MyList) interfaceType) .GetProperty (" Count ")' fa quindi la chiamata a 'Count'work? – pasty
problemi simili qui - usando Invoke() sembra causare il marshalling che fa cadere l'esecuzione in questo VectorToCollectionAdapter che poi barfs con il messaggio "L'oggetto non corrisponde al tipo di destinazione". (perché un IVector non è un ICollection). Considero questo un bug. – fusi