Ich bin mir ziemlich sicher, dass ich irgendwo einen Zwang oder eine Einschränkung verpasse, aber hier ist meine Situation. Angenommen, ich habe eine Klasse, die ich für einen Proxy haben will, wie folgt aus:Kann ich Reflektionen mit RealProxy-Instanzen verwenden?
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.
}
ich einen Proxy für diese Klasse erstellt werden soll, so dass ich kann Methodenaufrufe abfangen und einige Verarbeitung auf dem zugrunde liegende Objekt durchführen . Hier ist meine Umsetzung:
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);
}
}
Schließlich habe ich eine Klasse, die die Proxy-Klasse verbraucht, und ich den Wert des MyList
Mitglied über Reflexion.
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);
}
}
Jetzt, wenn ich versuche, Reflektion zu verwenden, um auf das Proxy-Objekt zuzugreifen, stoße ich auf Probleme. Hier ein Beispiel:
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();
}
}
Versuch GetValue
auf der Count
Eigenschaft über Reflexion zu nennen wirft die folgende Ausnahme:
eine Ausnahme vom Typ ‚System.Reflection.TargetException‘ aufgetreten in mscorlib.dll wurde aber nicht im Benutzercode behandelt
Weitere Informationen: Das Objekt stimmt nicht mit dem Zieltyp überein.
Bei dem Versuch, den Wert der Count
Eigenschaft zu erhalten, anscheinend der Rahmen ruft in System.Runtime.InteropServices.WindowsRuntime.IVector
Sie die get_Size
Methode aufzurufen. Ich verstehe nicht, wie dieser Aufruf auf dem zugrunde liegenden Objekt des Proxys fehlschlägt (die tatsächliche Liste), um dies zu ermöglichen. Wenn ich keinen Proxy des Objekts verwende, funktioniert das Abrufen des Eigenschaftswerts über die Reflektion. Was mache ich falsch? Kann ich überhaupt tun, was ich erreichen will?
Bearbeiten: A bug has been opened in Bezug auf dieses Problem auf der Microsoft Connect-Website.
Beachten Sie, dass diese Implementierung nicht im Leerlauf Spekulation ist. [MbUnit 'Assert.Count' Methode] (https://github.com/Gallio/mbunit-v3/blob/master/src/MbUnit/MbUnit/Framework/Assert.Count.cs) tut dies für einige Sammlungen. Wenn das Sammlungsobjekt ein Proxy ist, wird der Aufruf von Assert.Count ausgelöst. – JimEvans
Ist es möglich, den 'MyListProxy.CreateProxy' generisch zu machen, so dass er den reellen Typ und nicht das Objekt zurückgibt? Für den Test: Wenn dieser Aufruf in main 'interfaceType.GetProperty (" Count ")' in '((MyList) interfaceType) geändert wird .GetProperty (" Count ")' funktioniert dann der Aufruf von 'Count'work? – pasty
Ähnliche Probleme hier - die Verwendung von Invoke() scheint Marshalling zu verursachen, was bewirkt, dass die Ausführung in diesen VectorToCollectionAdapter fällt, der dann mit der Meldung "Objekt stimmt nicht mit dem Zieltyp überein" abstürzt. (weil ein IVektor keine ICollection ist). Ich halte dies für einen Fehler. – fusi