Ich bin sicher, dass die Ursache für mein Problem ist, diese ähnliche Frage Kreuzung:Objekttyp kann nicht konvertiert werden Typ Ziel, wenn AppDomains
How do I pass references as method parameters across AppDomains?
und insbesondere this answer, aber ich bin nicht ganz sicher, wie man es repariert.
Das Problem, das ich habe, ist dies, ich habe eine Visual Studio-Erweiterung, die ich schreibe und eines der Dinge, die es in der Lage ist zu tun ist, lädt eine Baugruppe in eine separate Domäne (so kann ich es ablegen, wenn ich bin fertig damit und mache ein paar Sachen damit. Also ich habe meine Domain wie folgt aufgebaut:
// The actual ApplicationBase of the current domain will be the one of VS and not of my plugin
// We need our new AppDomain to be able to find our assemblies
var p = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var setup = new AppDomainSetup()
{
ApplicationBase = p
};
domain = AppDomain.CreateDomain("MyTest_AppDomain", AppDomain.CurrentDomain.Evidence, setup);
var t = typeof(Proxy);
proxy = domain.CreateInstanceAndUnwrap(t.Assembly.FullName,
t.FullName,
false,
BindingFlags.Default,
null,
new object[] { assemblyPath },
null,
null) as Proxy;
ich die ApplicationBase
setzen, die für sie in der Lage sein, meine Klasse zu laden Proxy
obwohl sie in derselben Anordnung wie der obigen Code definiert ist. Ohne dass ich war immer FileNotFoundExceptions
Nun meine Proxy
Klasse etwas wie folgt aussieht:
public class Proxy : MarshalByRefObject
{
private Assembly _assembly;
private IEnumerable<Type> _types;
public IEnumerable<Type> Types
{
get
{
if (_types == null && _assembly != null)
{
_spiders = _assembly.GetTypes().Where(t => typeof(IFoo).IsAssignableFrom(t)).ToList();
}
return _types;
}
}
public Proxy(string assemblyPath)
{
_assembly = Assembly.LoadFile(assemblyPath);
}
public IFoo GetInstanceOf(string fooType)
{
var type = Types.FirstOrDefault(t => t.FullName == fooType);
if (type == null)
{
throw new InvalidOperationException($"Unknown type {fooType} in assembly {_assembly.FullName}");
}
return GetInstanceOf(type);
}
private IFoo GetInstanceOf(Type fooType)
{
var obj = Activator.CreateInstance(fooType);
return obj as IFoo;
}
public override object InitializeLifetimeService()
{
return null;
}
}
Zurück in der gleichen Klasse, die die neuen AppDomain
und die Instanz von Proxy
in den neuen AppDomain
habe ich etwas wie dies:
public IFoo GetInstanceOf(Type type)
{
var name = type.FullName;
var foo = proxy.GetInstanceOf(name);
return foo;
}
Zunächst versuchte ich proxy.GetInstanceOf
Bestehen der Art direkt zu nennen, aber das hat nicht funktioniert wahrscheinlich fo Aus demselben Grund wie der Code, den ich habe, funktioniert nicht. Als ich in der Linie var foo = proxy.GetInstanceOf...
Linie erhalten erhalte ich ein ArgumentException
mit der Meldung:
Objekttypen nicht Typ Ziel umgewandelt werden kann.
Ich glaube, das Problem ist, weil die IFoo
in MyTest_AppDomain
ist nicht die gleiche wie IFoo
in DefaultDomain
zu dem Ergebnis, aber ich bin nicht sicher, was der richtige Weg, dies zu beheben.
Es kann relevant sein, dass IFoo
selbst in einer separaten dritten Assembly definiert ist, die sowohl mein VSIX-Projekt als auch die Assembly, die ich in einer separaten Domäne laden möchte, referenzieren. Ich muss überzeugen, ich denke, MyTest_AppDomain
, um die gleiche IFoo
Assembly von der gleichen Stelle wie DefaultDomain
zu laden, oder sonst überzeugen, dass sie ein und dasselbe sind.
Hinweis: Alle meine Klassen, die IFoo
implementieren, erben von einer abstrakten Basis FooBase
, die wiederum von MarshalByRefObject
erbt.
bearbeiten mehr über dieses Denken mein Problem könnte von hier kommen:
_assembly = Assembly.LoadFile(assemblyPath);
Die assemblyPath
gibt es einen anderen Weg zum ApplicationBase
und dieser Weg hat seine eigene Version von foo.dll
ist (wo IFoo
definiert ist). Also vielleicht lädt es von dort vor dem Laden von ApplicationBase
?In Proxy.GetInstanceOf
kann ich typeof(IFoo).Assembly.Location
betrachten und es gibt mir den erwarteten Pfad, der in ApplicationBase
festgelegt wurde, aber ich glaube nicht, wenn meine Assembly geladen wird, wird es foo.dll
von dort bekommen.
Möchten Sie, dass IFoo als Referenz erstellt wird oder erwarten Sie eine neue Kopie in Ihrer Anwendungsdomäne? Sie tun das erste mit MarshalByRef, also gehe ich davon aus, dass Sie eine neue Kopie wollen (aber nur für den Fall fragen). Stellen Sie sicher, dass alles, was von IFoo implementiert wird, serialisierbar ist, da die Instanz serialisiert und deserialisiert werden sollte, wenn sie Anwendungsdomänen kreuzt. – Igor
@Igor: Ich möchte eine Instanz in der neuen App-Domäne erstellen und einen Verweis darauf an die Standarddomäne übergeben, damit ich Methoden aufrufen und einige Ereignisse abonnieren kann. –
Das funktioniert nicht (standardmäßig). Anwendungsdomänen verwenden .Net-Remoting, um miteinander zu kommunizieren. Instanzen, die zwischen Anwendungsdomänen übergeben werden, sind im Wesentlichen Kopien. Wenn Sie "IFoo" zurückgeben, erhalten Sie eine Kopie von "IFoo", keine Referenz auf die in Ihrer anderen Anwendungsdomäne (standardmäßig) erstellte Instanz, so dass Sie keine Ereignisse auf IFoo oder Aufrufmethoden abonnieren und die Instanz in Ihrem erwarten können App-Domäne erstellt, um diese Methoden zu verarbeiten. (mehr zu kommen ...) – Igor