I have a class I am attempting to instantiate through the use of Assembly and Activator, this class implements an interface, however when I run the instance of the class through a conditional that checks that the class implements it, I am getting false. What could be the problem?
My code where I am checking for implementation:
string className = MyClass;
Type type = null;
Assembly assembly = Assembly.LoadFile("#C:\\MyDLL", new Evidence(AppDomain.CurrentDomain.Evidence));
type = assembly.GetType(className);
object instance = Activator.CreateInstance(type);
//never makes it past this conditional
if (!(instance is MyInterface)
{
//It always endsup in here, when it shouldn't.
System.Writeline("ERROR");
}
else{
//This is what needs to happen
}
Code for the class MyClass that is outside the scope of all of this, and in MyDLL
public class MyClass: MyInterface
{
//Contents irrelevent to my problem
}
I am at a loss as to why this is not passing the conditional. Could I be instantiation the class wrong? Also to note I am a huge rookie when it comes to using Assembly/Activator and using interfaces.
Most likely reason - both DLL and your code have own version of MyInterface. This could happen either because
one did not want to spend time to come up with good unique name for interface,
someone decided to share interface as source instead of via assembly reference,
good named interfaces in the different namespaces and you are using the wrong one.
You may be referencing your assembly directly. If so, the types you load dynamically will have the identical name and namespace, but are considered different by the runtime.
Related
I have a class (TabControlH60) that both inherits from a base class (UserControl) and implements an interface (IFrameworkClient). I instantiate the object using the .NET Activator class. With the returned instance, I can cast to the UserControl base class, but not to the interface. The exception I get is below the code snipet. How do I cast to the interface?
object obj = Activator.CreateInstance(objType);
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient
m_Client = (UserControl)obj; // base class cast works
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails
// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window.
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type
'FPG.AFF.Interfaces.IFrameworkClient'."}
I hat the same problems with a library of mine providing "plugin"-functionality... I got it finally working...
Here was my problem: I had one main assembly using plugins, one assembly with the plugin (Plugin.dll) AND (important) another assembly providing the plugin-functionality (Library.dll).
The Plugin.dll referenced the main assembly (in order to be able to extend it) and the Library.dll with the plugin-func. - it's binaries got to a directory "./Plugins" relative to the main assembly.
The main assembly also referenced the plugin-func. assembly in order to use the "PluginManager" is wrote. This "PluginManager" gets a path and loads all *.dll files via reflection in order to analyze if there is a "IPlugin"-interface (which comes from Library.dll too).
Everytime I called the PluginManager to load the plugins it could not cast them to "IPlugin" although they implemented it.
I nearly got mad - but then I found out the whole problem. By compiling the plugin there was not only the "Plugin.dll" but the "Library.dll" written to the "./Plugins" directory. By accidentally loading the "Library.dll" every time with my PluginManager I now had two types of "IPlugin" - one in the actual "Library.dll" that is used from the main assembly and one that was loaded through my PluginManager - and those were incompatible!
Attention - if you just do not load "./Plugins/Library.dll" you nevertheless encounter the problem - because if you load "Plugin.dll" which references "Library.dll" then it just uses the one in the same directory... TILT...!! My PluginManager now just deletes "Library.dll" where it find it.
The clue is: Be sure that you do not access two assemblies in different contexts!
The most likely cause here is that IFrameworkClient is from a different assembly in the two cases, and is thus a different .NET type. Even if it is the same code, it can be a different type.
Check the AssemblyQualifiedName. Note also that if you are loading this assembly with reflection you can get a different type even with the same AssemblyQualifiedName, thanks to the load-context.
Define IFrameworkClient Interface in independent namespace (must be have namespace) of independent project (class library).Then add refrence of the class library to Control project and main project
When the Interface is in a different assembly and i get my class dynamically at run-time in a different assembly, interface casting will be failed like your sample (C# knows our interface as a different type than which one the class inherited from that).
This is my simple and useful technique in this cases:
When I'm sure my Class has inherited from the mentioned Interface (eq. IFrameworkClient), so i write one magic line of code like this:
dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;
By this technique you can:
Write your codes after this line of code for fc at design time base on Interface members info and vs editor intelligences system.
Prevent any interface casting error at run-time
Notes:
You need C# v4 to use dynamic type
Usually i don't like to use dynamic types in my codes but it can help us in some cases like this
Something tells me your sample code is leaving some stuff out...
class Program
{
static void Main(string[] args)
{
var type = typeof(MyClass);
object obj = Activator.CreateInstance(type);
Type[] interfaces = obj.GetType().GetInterfaces();
var m_Client = (UserControl)obj;
IFrameworkClient fc = (IFrameworkClient)obj;
}
}
public interface IFrameworkClient { }
public class UserControl { }
public class MyClass : UserControl, IFrameworkClient { }
This compiles and runs.
I'm betting that the DLL containing the definition of IFrameworkClient hasn't yet been loaded before you try to cast. This can happen when you're using Activator.CreateInstance.
Try inserting var forceLoad = typeof(IFrameworkClient); before the cast.
If the class FPG.H60.AFF.TabControlH60 actually does implement IFrameworkClient there should be no reason this would fail. The only thing I can think of that causes this exception is if the assembly that contains IFrameworkClient is strongly named and the Tab Control object happens to reference a different version of the containing assembly or your are using a different interface with the name IFrameworkClient.
In my case I had to add a build event to copy the needed DLL since I was creating instances and assigning to interface types at run time. Otherwise the DLL loaded might not be the most up-to-date DLL, and therefore may not cast to the interface.
The reason I used build events in this case (instead of adding the DLL as a reference) is that the architecture is such that the main application should only reference the interface types, and everything else should be loaded dynamically.
TLDR;
In the case of loading types dynamically from another DLL, make sure you copy the most recent version of that DLL to the bin directory using build events, otherwise casting may not work when it appears that it should.
I ran into same issue and I just added the following code
private void LoadAssemblyPlugins(string dll)
Assembly ass = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => new Uri(a.CodeBase).Equals(new Uri(dll)));
if (ass == null)
// Load it here
// use activator here
Although, in production it will never be a problem, in unit test it was but now I don't need to load it again and create a "different type"
The cast isn't working because you're trying to cast from type object to the interface. If you replace the interface cast line with:
IFrameworkClient fc = (IFrameworkClient)m_Client;
It will work.
Alternately, I'm mildly certain that you could do the cast from the object to the interface with the as operator.
See this article for more information:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
One more piece of the puzzle. Interfaces do not derive from object:
http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx
I'm trying to make an expansion setup for this game I'm developing, (not going to go into detail about), but all a single expansion will need is the 1 .dll file added into the Expansions folder I have added.
I have figured out how to access these .dll added into this folder as seen below:
Assembly ExpAssembly = Assembly.LoadFrom("Expansions/Intrique.dll");
Type myType = ExpAssembly.GetTypes()[0];
Here is an example of the class I'm trying to load:
public class Expansion: MyGame.Expansion {
public Expansion() {
//Stuff
}
public string SomeMethod()
{
return "Test";
}
}
Calling the following code runs SomeMethod() just fine
MethodInfo Method = myType.GetMethod("SomeMethod");
object myInstance = Activator.CreateInstance(myType);
MessageBox.Show(Method.Invoke(myInstance, null).ToString());
But what I want to do is be able to write Expansion expObj; and assign it by calling new Expansion() from this not-referenced .dll, but not in the library itself.
(For the purposes of this answer, I'm going to assume that your Expansion subclass is has a fully qualified name of Intrique.Expansion. I.e. the namespace is the same as the name of the DLL).
Because your main program does not reference Intrique.dll, the code in your main program cannot use the types in that DLL directly. That is, Intrique.Expansion is not a usable type in the context of the written code of your main program, though it can be used at run-time.
Taking your code example literally, the only approach likely to work given the code you have now would be to use dynamic:
dynamic myInstance = Activator.CreateInstance(myType);
myInstance.SomeMethod();
This is because SomeMethod() is declared only in Intrique.Expansion. There's not any other type you could use statically in your main program where that method is known.
If that method was instead an implementation of a member of some interface that Intrique.Expansion implements and which your main program references, or was an override of some virtual member of MyGame.Expansion (which presumably your main program references, if not actually declares), then you could cast the instance to the interface type or MyGame.Expansion respectively and call the method that way:
ISomeInterface myInstance = (ISomeInterface)Activator.CreateInstance(myType);
myInstance.SomeMethod();
or:
MyGame.Expansion myInstance = (MyGame.Expansion)Activator.CreateInstance(myType);
myInstance.SomeMethod();
Finally, given that you are trying to implement some kind of extensibility architecture, you might consider using the Managed Extensibility Framework, which is designed specifically to handle a lot of the messy parts of exactly this kind of thing.
While doing something almost completely irrelevant, a question popped into my head:
Can an expression of the form obj.GetType().IsInterface ever be true in a codebase consisting exclusively of C# code?
I suspect the answer is no, because:
GetType() will always return the runtime type.
The runtime type for concrete types matches the invoked constructor. Thus, it is never an interface, because interfaces don't have constructors.
Anonymous types cannot implement an interface (and if they did, they'd still have their anonymous class type).
Instances of internal classes of other assemblies implementing public interfaces will still have the class as the runtime type.
Using [ComImport, CoClass(typeof(MyClass))] on an interface makes it look like you can instantiate it, but the constructor call actually instantiates the referenced class.
I can't think of any other case. Am I missing something, or is my guess correct?
Can an expression of the form obj.GetType().IsInterface ever be true in a codebase consisting exclusively of C# code?
Yes - but probably not the way you were thinking of:
using System;
public class EvilClass
{
public new Type GetType()
{
return typeof(IDisposable);
}
}
class Test
{
static void Main()
{
EvilClass obj = new EvilClass();
Console.WriteLine(obj.GetType().IsInterface); // True
}
}
Slightly similarly, I believe you could create a subclass of RealProxy which would intercept the call and return an interface type.
If you mean "will the return value of the GetType() method declared in object ever be an interface type" - in that case I suspect the answer is no.
I'm trying to load a type from a different assembly (not known at build time) as 'dynamic' and execute a method on that type. My goal is to completely disconnect the 'plugin' from the parent application such that there is no requirement for any shared code or common interface type. The interface is implied by way of an expected method signature on the loaded type.
This works:
dynamic myObj = Assembly.Load("MyAssembly").CreateInstance("MyType");
myObj.Execute();
However this will load the type into the current AppDomain along with all its dependent assemblies.
I want to modify this to allow me to do that same thing in a separate AppDomain.
This works but doesn't make use of the dynamic keyword, I need to know the explicit type that I am instantiating to be able to call the Execute method:
var appDomain = AppDomain.CreateDomain(domainName, evidence, setup);
var myObj = appDomain.CreateInstanceAndUnwrap(assembly, type);
typeof(IMyInterface).InvokeMember("Execute", BindingFlags.InvokeMethod, null, myObj);
This is essentially my target case and I have been trying to get something like this working:
dynamic myObj = ad.CreateInstanceAndUnwrap(assembly, type);
myObj.Execute();
I keep ending up with a RuntimeBinderException with the message "'System.MarshalByRefObject' does not contain a definition for 'Execute'". This message makes sense, sure it doesn't contain a definition for 'Execute', but I know the type that I am instantiating does indeed contain an 'Execute' method. I imagine there's something going on here with the transparent proxy that is preventing this from working but I'm not sure what.
My actual class that I am trying to instantiate looks like this:
[Serializable]
public class MyClass : MarshalByRefObject {
public void Execute() {
// do something
}
}
I have also tried this with a shared interface (not my primary goal, but I'm trying to figure this out first) so it would look like:
[Serializable]
public class MyClass : MarshalByRefObject, IPlugin {
public void Execute() {
// do something
}
}
Where IPlugin is a known type in the parent application and the plugin has the appropriate reference at build time but this doesn't seem to work either.
I'm guessing at this point that it's not possible to load a type as dynamic across the AppDomain boundary.
Is there a way to actually get this to work?
As leppie indicated, you'll have to implement the IDynamicMetaObjectProvider interface to wrap the proxy that's being returned to you, and then you can use make dynamic calls on that.
In your implementation, you'd want to take the wrapped proxy and forward all calls to the static ExecuteMessage method on the RemotingServices class, which will take your proxy, as well as an IMethodCallMessage interface implementation.
Note that implementing the IMethodCallMessage interface is not trivial. Also, you'd have to properly interpret the IMethodReturnMessage interface implementation to get the return value, ref and out parameters correctly (if any).
That said, it's generally a better idea to provide an assembly that contains only an interface for the client and server to assume; if a method is changed in any way on the server side, even though the client side uses dynamic, you'd still have to change the call site to accommodate the change. At least with the interface, you get some type of compile-time check, which is always preferred to a run-time error.
I have a set of classes, each one is a different strategy to do the same work.
namespace BigCorp.SuperApp
{
public class BaseClass { }
public class ClassA : BaseClass { }
public class ClassB : BaseClass { }
}
The choice of which strategy to use is configurable. I want to configure only the class name 'ClassB' instead of the full type name 'BigCorp.SuperApp.ClassB' in the app.config file.
<appConfig>
<SuperAppConfig>
<Handler name="ClassB" />
</SuperAppConfig>
</appConfig>
However, the reflection calls fail because they expect the full type name, particularly
Type t = Type.GetType("ClassB"); // results in t == null
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails
How can I get this to work while configuring only the class name? Concatenate the namespace to the class name for full type name? Is there another reflection call that works?
If you think this is useless and I should expect the configuration to contain the full type name, I am open to that solution! Just provide rationale to convince me.
(I will not be loading a type from outside this assembly/namespace)
Either use the assembly-qualified-name, or get hold of the Assembly and use Assembly.GetType(name). In this case, since you want the types in the config file, assembly-qualified is a valid way to go - but since you know all your types are in the same assembly:
Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly!
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);
The static Type.GetType(string) has probing rules that often cause confusion... it looks at the calling assembly, and a few system assemblies - but not all loaded assemblies.
Since you know all classes will be coming from the same namespace, configure it once and use that:
<appConfig>
<SuperAppConfig handlerNamespace="BigCorp.SuperApp">
<Handler class="ClassB" />
</SuperAppConfig>
</appConfig>
Edit: I changed name to class to better denote the meaning of that attribute.
(I will not be loading a type from outside this assembly/namespace)
because of the above line, it is safe to assume that you know what the namespace is. Couldn't you do something like:
Type t = Type.GetType("Namespace." + className);
BaseClass c = Activator.CreateInstance(t) as BaseClass;
If you expect to possibly be able to add additional strategy classes to be loaded in the future, perhaps via an additional assembly, you would need to fully qualify your class name. This is recommended anyway, since you would be able to provide enhanced extendability for your application.
I'm going with the full type name in the application configuration. Below is a slightly more complete, but still trivial example
<SuperAppConfig>
<ObjectConfig provider="BigCorp.SuperApp.ClassA">
<add name="one" />
<add name="two" />
</ObjectConfig>
</SuperAppConfig>
And the factory class that actually creates this
private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
Type t = a.GetType(providerName)
IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
return o;
}
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails
Might also result from the fact, that CreateInstance does not return an instance of BaseClass, rather than an instance of BaseClass wrapped into an ObjectHandle.
Cast into your BaseClass after you used the UnWrap method.