I'm completely new to loading in libraries like this, but here's where I stand:
I have a homemade DLL file it's about as simple as it gets, the class itself and a method. In the home program that loads this library, I have:
Assembly testDLL = Assembly.LoadFile("C:\\dll\\test.dll");
From here, I'm kind of stuck. As far as I know, it's loading it correctly because it gives me errors when I change the name.
What do I do from here? How exactly do I load the class & methods within it?
Thanks.
Use Assembly.GetTypes() to get a collection of all the types, or Assembly.GetType(name) to get a particular type.
You can then create an instance of the type with a parameterless constructor using Activator.CreateInstance(type) or get the constructors using Type.GetConstructors and invoke them to create instances.
Likewise you can get methods with Type.GetMethods() etc.
Basically, once you've got a type there are loads of things you can do - look at the member list for more information. If you get stuck trying to perform a particular task (generics can be tricky) just ask a specific question an I'm sure we'll be able to help.
This is how you can get the classes if you know the type.
Assembly assembly = Assembly.LoadFrom("C:\\dll\\test.dll");
// Load the object
string fullTypeName = "MyNamespace.YourType";
YourType myType = assembly.CreateInstance(fullTypeName);
The full type name is important. Since you aren't adding the .dll you can't do a Using because it is not in your project.
If you want all I would just Jon Skeet answer.
If you want to dynamically load an assembly, and then invoke methods from classes therein, you need to perform some form of dynamic invoke.
Check here for basic advice on that.
The only bit missing is how to get the type itself, which can easily be retrieved wth code like this:
foreach (Type t in assemblyToScan.GetTypes())
{
if(condition)
//do stuff
}
And if you simply want to use the assembly statically (by having the assembly available at compile time), then the answer fom Launcy here on this page is the way to go.
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.
Following up on InternalsVisibleTo. I have looked at c# Instantiating Internal class with private constructor, and this has helped but I'm trying to cast the returned object as the internal type and, honestly I'm not 100% that that is possible.
I'm trying the route of Reflection to fix this issue, but I'm having a tough time trying to figure out how to instantiate an internal type with private methods using reflection. I can go as far as pulling the type and getting the constructor and creating an object.
How would I preform the cast of the object if the type I wish to cast is an internal type.?
public object InitPrivateCoreObjects(string Type)
{
Assembly Core = Assembly.Load("Stuff.Core, Version=0.3.3881.21340, Culture=neutral, PublicKeyToken=4fe470e63e2d354e");
Type TypeToReflect = Core.GetType("Stuff.Core.AssemblyWithIdentifer");
object o = Activator.CreateInstance(TypeToReflect);
MethodInfo mi = TypeToReflect.GetMethod("AssemblyWithIdentifer");
object newObject = mi.Invoke(o,null);
//alternatively
//ConstructorInfo ctor = TypeToReflect.GetConstructor(new Type[]{TypeToReflect.GetType()});
//ctor.Invoke(newObject, null);
return newObject;
}
I can get the type of the internal class,
I can call the constructor and instantiate an object of the type. However, since I don’t have any access to the internal type I can’t cast it and manipulate it from there.
I understand I can use Reflection.Emit to create a new class based on that type, but if I'm going that route then I might as well just copy the entire contents of the project I'm trying to access into my test project. This would be really wastefully and pointless and would require me to throw in stuff from other projects and creating a mess and it's absolutely not the route I want to go at this time.
I've seen examples accessing individual methods and properties but none that instantiate an entire class. I'm not 100% sure it's possible since in the order of operations reflection happens before access modifiers are looked at.
Can this be done, and if so, how?
For clairification sake I wanted to use the instantiated object for testing purposes and [Assembly:InternalsVisibleTo("")] wasn't working due to bug which I'm currently working around. See here for original question.
Given that you only know the type at execution time, there's really no such concept as "returning the object as the internal type". Think about what you'd want the method signature to look like... there's no way you could express it.
If the calling code knows about it in a strongly typed way, you should make the code generic instead:
public T InitPrivateCoreObjects<T>()
{
Type type = typeof(T);
...
return (T) newObject;
}
... but if the calling code doesn't know about it, that's not helpful to it.
If you could explain more about why you think you want this ability, we could try to suggest alteratives.
I can use Reflection.Emit to create a new class based on that type
Not really: code generated using Reflection.Emit follows the same rules as your own C#. You can't use it to bypass internal protection.
I've seen examples accessing individual methods and properties
That's what you'll need to do: use reflection to look up and invoke individual methods and properties.
A couple of alternatives:
Modify the internal class to implement some interface, and make that interface public. Call methods on the interface as normal.
Get [InternalsVisibleTo] working. This is the right way to go.
This is not really a direct answer to your question, but you may find this useful:
ExposedObject
If you don't have access to the internal type, nor does that type implement any public interface that you consider sufficient to interact with it, but you know beforehand the names and signatures of members on that type, this is probably your best choice.
I've been trying to sign an assembly and getting this error:
'Utils.Connection' does not implement interface member 'Interfaces.IConnection.BugFactory()'. 'Utils.Connection.BugFactory()' cannot implement 'Interfaces.IConnection.BugFactory()' because it does not have the matching return type of 'ThirdPartyLibrary.BugFactory'.
That error looks like a dirty, dirty lie! In Utils.Connection, I have this method:
public new BugFactory BugFactory()
I don't think the new keyword is the problem because 1) removing it doesn't stop the error and 2) I'm having the same error with another class that implements IConnection that does not use the new keyword. Update: if I use override instead of new, I get this error:
'Utils.Connection.BugFactory()': cannot override because 'ThirdPartyLibrary.ConnectionClass.BugFactory' is not a function
This is because ThirdPartyLibrary.ConnectionClass.BugFactory is a property.
There is only one BugFactory class, so it isn't a problem of the interface requiring a different BugFactory return type than what the method returns. Even if I explicitly mark my method as returning ThirdPartyLibrary.BugFactory, I still get the error when I try to strong-name the Utils DLL.
Could this be the result of ThirdPartyLibrary being an old COM library that is not CLS-compliant? I have no control over this library. When I do not try to sign the Utils assembly, I do not get the interface error.
My big question is: how can I sign this assembly?
Edit: here's what IConnection has:
using ThirdPartyLibrary; // The only using statement
namespace Interfaces
{
public interface IConnection
{
...
BugFactory BugFactory();
}
}
I'm still suspicious of the new keyword for this error.
You say "I don't think the new keyword is the problem because 1) removing it doesn't stop the error", but you must bear in mind that if your method hides a base method, the compiler will add a new, even if you don't specify it, unless you explicity specify override instead.
All the explicit new does is to prevent a compiler warning (not an error).
Is there really a method to hide or override at all?
What happens if you specify virtual instead of new on this method. Does it compile? Does it error with "no suitable method found to override?"
[Edit in response to your comment]
I get this error:
"'Utils.Connection.BugFactory()':
cannot override because
'ThirdPartyLibrary.ConnectionClass.BugFactory'
is not a function." The original
ThirdPartyLibrary.ConnectionClass.BugFactory
is a property.
I suspect this may be the issue. You are overriding a property with a method.
By using the new keyword, you are hiding the old property to anyone that has a reference to your derived class.
By contrast, anyone that has a reference cast as the superclass (the one you are inheriting from), they will see the old property, and not your new method.
Can you give some more code of the superclass (or interface) together with the derived class?
[Edit in response to your comment]
I'm trying to change the interface to
have BugFactory be a property instead
of a method
The trouble with new is that it seems like a bit of magic, that can let you change argument types and return types, but it is really pure evil.
Instead of changing the types for all consumers of the code, it only does it for consumers that are cast as the overriding new type. This gets you in the horrible position where two consumers to the same instance will see different signatures depending on how they are cast.
See if you can identify the consuming code that is complaining, and have a think around whether more of your code needs to change to support the type changes. Also, is there the possibility that you are trying to do something that is "a bit of a nasty hack"?
Namespace/version problems?
ThirdPartyLibrary.BugFactory might be a different type, if you have two different versions of the 3rd party assembly being referenced somehow: One during compile time and a different one when you sign/verify..
It sounds like you are simply referencing the COM library through the Add Reference dialog. You should probably create a Primary Interop Assembly for the COM library which can be signed. One of the caveats of signing an assembly is that all the assemblies it references must also be signed.
You would normally use the SDK program TlbImp:
TlbImp yourcomlibrary.tlb /primary /keyfile:yourkeyfile.snk /out:yourcomlibrary.dll
What does your IConnection interface look like? It seems like your ThirdPartyLibrary has a BugFactory object and you also have a BugFactory object either in your project or another reference. Did you try changing both the interface and the concrete type to explicity use ThirdPartyLibrary.BugFactory as the return type for that method?
I'm making a simple test object-oriented program to try and help me get to grips with OOP. I've got an ICommand inteface which has the method Run(params object[] parameters) and I have various classes that use that interface and implement their own versions of run. Each class also has a name property which says what the command is and what it does.
I want to have a GUI where I can create commands, which presumably will need some sort of listbox to select what type of command to create. The question is, how do I make that listbox and make it work without hardcoding in a switch statement with explicit references to all of the classes I've created.
I'm sure this is a really simple problem that I should know the answer to, but I just can't think of it! I'm sure there is an answer though.
Oh and I expect some of the responses will say to read the Design Patterns book: well the only copy in the library is out at the moment, but I will be reading it asap!
Update: I've just posted a follow up question here
Store all your classes in a generic list of ICommand , override ToString() with the name of your command and apply the contents of the list to your listbox.
var commandlist = new List<ICommand>();
commandList.add(new Command("Run"));
commandList.add(new Command("Walk"));
commandList.add(new Command("Crawl"));
use the strategy pattern (link to wikipedia), you'll execute the method via invoke or reflection.
Since there are a lot of examples i won't list here.
I'm not sure you really need to avoid the explicit invocation of constructors. However, you can do it through reflection - if the constructors of your types don't need any arguments:
var commands = new List<object>();
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in assembly.GetTypes())
{
if (type.GetInterface(typeof(ICommand).FullName) != null)
{
commands.Add(Activator.CreateInstance(type));
}
}
}
This code assumes the assemblies defining the ICommand implementations are already loaded and does not do any desired error handling.
Another approach is to read a configuration file with the names of the types to instantiate (and maybe even of assemblies to load).
However, in most cases there is no need for this. It's typically quite alright to have a CommandFactory class which just calls a bunch of constructors.
You could use reflection to find all the classes that implement the interface you're interested in; then use that to populate your list