I'm trying to load some .dll files dynamically. The Files are Plugins (self-written for now) which have at least one class that implements MyInterface. For each file I'm doing the following:
Dictionary<MyInterface, bool> _myList;
// ...code
Assembly assembly = Assembly.LoadFrom(currentFile.FullName);
foreach (Type type in assembly.GetTypes())
{
var myI = type.GetInterface("MyInterface");
if(myI != null)
{
if ((myI.Name == "MyInterface") && !type.IsAbstract)
{
var p = Activator.CreateInstance(type);
_myList.Add((MyInterface)p, true);
}
}
}
Running this causes a cast exception, but I can't find a workaround. Anyway I am wondering why this doesn't work at all. I'm looking for a solution in .NET Framework 3.5.
Another thing that happened to me was getting null in p after running the following at the point before adding a new entry to _myList in the code above:
var p = type.InvokeMember(null, BindingFlags.CreateInstance, null,
null, null) as MyInterface;
This code was the first attempt on loading the plugins, I didn't find out why p was null yet.
I hope someone can lead me to the right way :)
There's much easier way to check if your type can be casted to your interface.
Assembly assembly = Assembly.LoadFrom(currentFile.FullName);
foreach (Type type in assembly.GetTypes())
{
if(!typeof(MyInterface).IsAssignableFrom(type))
continue;
var p = Activator.CreateInstance(type);
_myList.Add((MyInterface)p, true);
}
If IsAssignableFrom is false, there's something wrong with your inheritance, which is most likely cause of your errors.
You should really read Plug-ins and cast exceptions by Jon Skeet which explains the behaviour you see and how to do plug-in frameworks properly.
Please look into the following code. I think Type.IsAssignableFrom(Type type) can help you out in this situation.
Assembly assembly = Assembly.LoadFrom(currentFile.FullName);
///Get all the types defined in selected file
Type[] types = assembly.GetTypes();
///check if we have a compatible type defined in chosen file?
Type compatibleType = types.SingleOrDefault(x => typeof(MyInterface).IsAssignableFrom(x));
if (compatibleType != null)
{
///if the compatible type exists then we can proceed and create an instance of a platform
found = true;
//create an instance here
MyInterface obj = (ALPlatform)AreateInstance(compatibleType);
}
Related
Type type = typeof(MyType);
Type copy = type.Assembly.GetType(type.Name);
It seems trivial to me that above code should end up with copy being another reference to the same object as type. However, I keep getting copy == null. If I use the overload Assembly.GetType(type.Name, true) it throws a TypeLoadException.
Isn't it weird that the assembly of the type can't find this type? It's definitely in there though! The following are both true:
type.Assembly.GetTypes()[0] == type;
type.Assembly.GetExportedTypes()[0] == type;
If this is expected behavior, can anyone explain why so?
If it is not, could anyone point me to anything that may cause this to happen?
Super simple demo:
public class Program
{
static void Main(string[] args)
{
var type = typeof(Program);
Console.WriteLine(type.Assembly.GetExportedTypes()[0] == type); // True
Console.WriteLine(type.Assembly.GetType(type.Name, true)); // exception
}
}
Type.Name isn't quite enough to identify the type.
For example, typeof(string).Name will give you String - but there's no namespace.
To get the full type name including the namespace, you need to use Type.FullName instead. If you also care about different assemblies, a fully qualified name is the best - Type.AssemblyQualifiedName.
A few examples of the use of Type.GetType:
var a = Type.GetType("String"); // Returns null - not enough information to find the type
var b = Type.GetType("System.String"); // typeof(string), because mscorlib is loaded
var c = Type.GetType("System.Windows.Forms.Form, System.Windows.Forms");
// Works even when System.Windows.Forms isn't loaded
var d = Type.GetType("System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
// Also checks for proper version and signature.
// This is System.Windows.Forms from Microsoft.
As from the docu of Assembly.GetType:
This method only searches the current assembly instance. The name parameter includes the namespace but not the assembly.
Having said this provide the FullName of the given type:
Type type = typeof(MyType);
Type copy = type.Assembly.GetType(type.FullName);
You need to specify theFullName of your type:
var copy = type.Assembly.GetType(type.FullName)
How do I determine if a property is a user-defined type? I tried to use IsClass as shown below but its value was true for String properties (and who knows what else).
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass) {
// do something with property
}
}
* Updated for more clarity *
I am trying to traverse a given type's definition and if the given type or any of its public properties are defined within the assembly, I am searching for an embedded JavaScript document. I just don't want to waste processing resources and time on native .NET types.
#Bobson made a really good point:
"...Unlike some other languages, C# does not make any actual
distinction between "user-defined" and "standard" types."
Technically, #Bobson gave the answer; there is no distinguishing difference between a user-defined type and one defined in the .NET Framework or any other assembly for that matter.
However, I found a couple useful ways to determine if a type is user-defined.
To search for all types defined within the given type's assembly, this works great:
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass
&& property.PropertyType.Assembly.FullName == type.Assembly.FullName) {
// do something with property
}
}
If the types can be defined in various assemblies, excluding the System namespace works in most cases:
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass
&& !property.PropertyType.FullName.StartsWith("System.")) {
// do something with property
}
}
If by "user-defined" you mean that it is not part of the standard assembly (mscorlib) then you can do something along the lines of this:
if(typeof(SomeType).Assembly.GetName().Name != "mscorlib") {
// user-defined!
}
However this will also consider types from external assemblies (aka: libraries) to be considered "user-defined". If you only want those in your current assembly then you can use
typeof(SomeType).Assembly == Assembly.GetExecutingAssembly()
I wrote a generic populator for unit testing that assigns predictable values to my objects and came across this kind of problem. In my case I wanted to know which of my properties were objects so that I could recursively populate those object properties, again with predictable values.
It seemed to me that introducing an interface implemented only by the classes that I was interested in traversing was the best way to do this. You can then test to see if your property is an object of interest:
public static bool IsMyInterface(this Type propertyType)
{
return propertyType.GetInterface("MyInterfaceName") != null;
}
Say your project is named "Foobar" and everything you make is under that namespace. You can test to see if you've written it by the following method:
typeof(SomeType).Namespace.Contains("Foobar");
I struggled with this as well when creating a log when updating the database. I did not want the classes to be shown in the log as they never == between data and dto.
foreach (PropertyType item in properties)
{
if((item.PropertyType.IsClass && item.PropertyType.FullName.StartsWith("System.")) || !item.PropertyType.IsClass)
{
//...do stuff
}
}
This allowed me to deal with strings and the likes which are flagged as classes.
If by "user-defined" type you mean type that was declared in your executing assembly then you can obtain list of that types like in this sample c# console application:
class Program
{
static void Main( string[] args )
{
var currentAssembly = Assembly.GetExecutingAssembly();
var localTypes = currentAssembly.GetTypes();
}
}
UPDATE:
If you want to obtain list of types from all referenced assemblies:
class Program
{
static void Main( string[] args )
{
var currentAssembly = Assembly.GetExecutingAssembly();
var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
var typesFromReferencedAssemblies = referencedAssemblies.Select( assemblyName => Assembly.ReflectionOnlyLoad( assemblyName.FullName ) ).SelectMany( assembly => assembly.GetTypes() );
}
}
Just be aware that Program type will also be in that list. Is this sufficient answer to your problem?
I'm trying to load and use a DLL at runtime and this works fine:
var pluggin = asm2.CreateInstance("ParserTest.Interface", true) as iPluggin;
But this doesn't (I need to loop through the DLL files in a specific folder to find the right ones implementing iPluggin interface):
...
var asm = Assembly.LoadFrom(dll.FullName);
if (asm.GetExportedTypes().FirstOrDefault(q => q.GetInterface(tName) != null) == null) continue;
Project.ProcessList.Add(asm.CreateInstance(tName, true) as iPluggin);
...
Doing some research in debug mode I found out that:
asm.CreateInstance(tName, true)
returns the correct object, but when trying to cast it to iPluggin the result is null.
Any idea why?
I did something similar:
private readonly Type _pluginbaseType = typeof(BasePlugin);
public AssemblyPlugin(Assembly assembly)
{
Type[] _plugins = _assembly.GetExportedTypes()
.Where(t => t.BaseType.IsSubclassOf(_pluginbaseType)
.ToArray();
}
After this you can:
BasePlugin plugin = (BasePlugin)Activator.CreateInstance(pluginType);
You should prefer a base class instead of an interface.
Mistery solved althought I don't understand it.
The DLL that defines de interface (SDK.dll) was among the ones being checked.
I removed it manually in my query and all woks as expected now.
This is my final code:
var plugins =
from fi in di.GetFiles("*.dll").Where(p => p.Name.ToUpper() != "SDK.DLL")
let asm = Assembly.LoadFrom(fi.FullName)
from t in asm.GetExportedTypes()
where t.GetInterface(typeof(iPluggin).Name) != null
select asm.CreateInstance(t.FullName, true) as iPluggin;
Project.ProcessList.AddRange(plugins);
Question based on MSDN example.
Let's say we have some C# classes with HelpAttribute in standalone desktop application. Is it possible to enumerate all classes with such attribute? Does it make sense to recognize classes this way? Custom attribute would be used to list possible menu options, selecting item will bring to screen instance of such class. Number of classes/items will grow slowly, but this way we can avoid enumerating them all elsewhere, I think.
Yes, absolutely. Using Reflection:
static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly) {
foreach(Type type in assembly.GetTypes()) {
if (type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0) {
yield return type;
}
}
}
Well, you would have to enumerate through all the classes in all the assemblies that are loaded into the current app domain. To do that, you would call the GetAssemblies method on the AppDomain instance for the current app domain.
From there, you would call GetExportedTypes (if you only want public types) or GetTypes on each Assembly to get the types that are contained in the assembly.
Then, you would call the GetCustomAttributes extension method on each Type instance, passing the type of the attribute you wish to find.
You can use LINQ to simplify this for you:
var typesWithMyAttribute =
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
The above query will get you each type with your attribute applied to it, along with the instance of the attribute(s) assigned to it.
Note that if you have a large number of assemblies loaded into your application domain, that operation could be expensive. You can use Parallel LINQ to reduce the time of the operation (at the cost of CPU cycles), like so:
var typesWithMyAttribute =
// Note the AsParallel here, this will parallelize everything after.
from a in AppDomain.CurrentDomain.GetAssemblies().AsParallel()
from t in a.GetTypes()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
Filtering it on a specific Assembly is simple:
Assembly assembly = ...;
var typesWithMyAttribute =
from t in assembly.GetTypes()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
And if the assembly has a large number of types in it, then you can use Parallel LINQ again:
Assembly assembly = ...;
var typesWithMyAttribute =
// Partition on the type list initially.
from t in assembly.GetTypes().AsParallel()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
Other answers reference GetCustomAttributes. Adding this one as an example of using IsDefined
Assembly assembly = ...
var typesWithHelpAttribute =
from type in assembly.GetTypes()
where type.IsDefined(typeof(HelpAttribute), false)
select type;
As already stated, reflection is the way to go. If you are going to call this frequently, I highly suggest caching the results, as reflection, especially enumerating through every class, can be quite slow.
This is a snippet of my code that runs through all the types in all loaded assemblies:
// this is making the assumption that all assemblies we need are already loaded.
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in assembly.GetTypes())
{
var attribs = type.GetCustomAttributes(typeof(MyCustomAttribute), false);
if (attribs != null && attribs.Length > 0)
{
// add to a cache.
}
}
}
This is a performance enhancement on top of the accepted solution. Iterating though all classes can be slow because there are so many. Sometimes you can filter out an entire assembly without looking at any of its types.
For example if you are looking for an attribute that you declared yourself, you don't expect any of the system DLLs to contain any types with that attribute. The Assembly.GlobalAssemblyCache property is a quick way to check for system DLLs. When I tried this on a real program I found I could skip 30,101 types and I only have to check 1,983 types.
Another way to filter is to use Assembly.ReferencedAssemblies. Presumably if you want classes with a specific attribute, and that attribute is defined in a specific assembly, then you only care about that assembly and other assemblies that reference it. In my tests this helped slightly more than checking the GlobalAssemblyCache property.
I combined both of these and got it even faster. The code below includes both filters.
string definedIn = typeof(XmlDecoderAttribute).Assembly.GetName().Name;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
// Note that we have to call GetName().Name. Just GetName() will not work. The following
// if statement never ran when I tried to compare the results of GetName().
if ((!assembly.GlobalAssemblyCache) && ((assembly.GetName().Name == definedIn) || assembly.GetReferencedAssemblies().Any(a => a.Name == definedIn)))
foreach (Type type in assembly.GetTypes())
if (type.GetCustomAttributes(typeof(XmlDecoderAttribute), true).Length > 0)
In case of the Portable .NET limitations, the following code should work:
public static IEnumerable<TypeInfo> GetAtributedTypes( Assembly[] assemblies,
Type attributeType )
{
var typesAttributed =
from assembly in assemblies
from type in assembly.DefinedTypes
where type.IsDefined(attributeType, false)
select type;
return typesAttributed;
}
or for a large number of assemblies using loop-state based yield return:
public static IEnumerable<TypeInfo> GetAtributedTypes( Assembly[] assemblies,
Type attributeType )
{
foreach (var assembly in assemblies)
{
foreach (var typeInfo in assembly.DefinedTypes)
{
if (typeInfo.IsDefined(attributeType, false))
{
yield return typeInfo;
}
}
}
}
This is another version of the code provided by Trade-Ideas philip,
I've condensed the code to linq, plugged it into a nice static function which you can just drop in the project.
Original:
https://stackoverflow.com/a/41411243/4122889
I've also added AsParallel() - on my machine with enough cores etc, and with a 'normally' sized project (which is completely subjective), this was the fastest/
Without AsParallel() this took 1,5 seconds for about 200 results, and with it, it took about a couple milliseconds - therefore this seems the fastest to me.
Note that this skips the assemblies in the GAC.
private static IEnumerable<IEnumerable<T>> GetAllAttributesInAppDomain<T>()
{
var definedIn = typeof(T).Assembly.GetName().Name;
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var res = assemblies.AsParallel()
.Where(assembly => (!assembly.GlobalAssemblyCache) && ((assembly.GetName().Name == definedIn) ||
assembly.GetReferencedAssemblies()
.Any(a => a.Name == definedIn))
)
.SelectMany(c => c.GetTypes())
.Select(type => type.GetCustomAttributes(typeof(T), true)
.Cast<T>()
)
.Where(c => c.Any());
return res;
}
Usage:
var allAttributesInAppDomain = GetAllAttributesInAppDomain<ExportViewAttribute>();
Note if you have only 1 attribute per class, so not multiple, its easier to flatten the result from IEnumerable<IEnumerable<T>> to IEnumerable<T> like so:
var allAttributesInAppDomainFlattened = allAttributesInAppDomain.SelectMany(c => c);
Remember, this uses IEnumerable so call ToList() to actually run the function.
We can improve on Andrew's answer and convert the whole thing into one LINQ query.
public static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly)
{
return assembly.GetTypes().Where(type => type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0);
}
Under a given namespace, I have a set of classes which implement an interface. Let's call it ISomething. I have another class (let's call it CClass) which knows about ISomething but doesn't know about the classes which implement that interface.
I would like that CClass to look for all the implementation of ISomething, instantiate an instance of it and execute the method.
Does anybody have an idea on how to do that with C# 3.5?
A working code-sample:
var instances = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.GetInterfaces().Contains(typeof(ISomething))
&& t.GetConstructor(Type.EmptyTypes) != null
select Activator.CreateInstance(t) as ISomething;
foreach (var instance in instances)
{
instance.Foo(); // where Foo is a method of ISomething
}
Edit Added a check for a parameterless constructor so that the call to CreateInstance will succeed.
You can get a list of loaded assemblies by using this:
Assembly assembly = System.Reflection.AppDomain.CurrentDomain.GetAssemblies()
From there, you can get a list of types in the assembly (assuming public types):
Type[] types = assembly.GetExportedTypes();
Then you can ask each type whether it supports that interface by finding that interface on the object:
Type interfaceType = type.GetInterface("ISomething");
Not sure if there is a more efficient way of doing this with reflection.
A example using Linq:
var types =
myAssembly.GetTypes()
.Where(m => m.IsClass && m.GetInterface("IMyInterface") != null);
foreach (Type t in Assembly.GetCallingAssembly().GetTypes())
{
if (t.GetInterface("ITheInterface") != null)
{
ITheInterface executor = Activator.CreateInstance(t) as ITheInterface;
executor.PerformSomething();
}
}
You could use something like the following and tailor it to your needs.
var _interfaceType = typeof(ISomething);
var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
var types = GetType().GetNestedTypes();
foreach (var type in types)
{
if (_interfaceType.IsAssignableFrom(type) && type.IsPublic && !type.IsInterface)
{
ISomething something = (ISomething)currentAssembly.CreateInstance(type.FullName, false);
something.TheMethod();
}
}
This code could use some performance enhancements but it's a start.
Maybe we should go this way
foreach ( var instance in Assembly.GetExecutingAssembly().GetTypes().Where(a => a.GetConstructor(Type.EmptyTypes) != null).Select(Activator.CreateInstance).OfType<ISomething>() )
instance.Execute();