How to find all the classes which implement a given interface? - c#

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();

Related

How can I assign a var to be one of two difference types based on a conditional?

I have two dictionaries, one for my file transfers I have as a host, and one for my file transfers I have as a client.
The code I'm doing for one of the areas of my program is entirely similar, with exception of referencing one of these items or the other. For this reason, I'm trying to prevent duplicating code if I can.
public void UpdateFileTransferItems(FileTransferItem.FileTransferRole role)
{
// If the role is Sender then the variable is fileTransferSessionsAsHost, otherwise it is fileTransferSessionsAsClient.
var fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost : fileTransferSessionsAsClient;
foreach (var hostSession in fileTransferSessions)
{
Do Work in here.
}
}
Obviously the ternary operator doesn't work, but how can I create code that will do what I am trying to do? If the role is of a sender, I want the variable to be a reference to fileTransferSessionsAsHost, otherwise I want it to be fileTransferSessionsAsClient.
Am I going about this in an obtuse way? Should I just duplicate the code and have two if statements?
EDIT:
This is what I'm having to do right now, if I can't figure out a better way. If you look, the code is identical for each one, with exception of the names and dictionary items reference.
public void UpdateFileTransferItems(FileTransferItem.FileTransferRole role)
{
if (role == FileTransferItem.FileTransferRole.Sender)
{
foreach (var hostSession in fileTransferSessionsAsHost)
{
var fileTransferItem = activeFileTransfers.FirstOrDefault(fti => fti.SessionId == hostSession.Key.SessionId);
if (fileTransferItem == null)
{
activeFileTransfers.Add(new FileTransferItem(hostSession.Key.FileName,
hostSession.Key.FileExtension,
hostSession.Key.FileLength,
FileTransferItem.FileTransferRole.Sender,
hostSession.Key.SessionId));
}
else
{
fileTransferItem.Update(hostSession.Value.TotalBytesSent,
hostSession.Value.TransferSpeed,
hostSession.Value.TotalBytesSent == hostSession.Key.FileLength);
}
}
}
else
{
foreach (var clientSession in fileTransferSessionsAsClient)
{
var fileTransferItem = activeFileTransfers.FirstOrDefault(fti => fti.SessionId == clientSession.Key.SessionId);
if (fileTransferItem == null)
{
activeFileTransfers.Add(new FileTransferItem(clientSession.Key.FileName,
clientSession.Key.FileExtension,
clientSession.Key.FileLength,
FileTransferItem.FileTransferRole.Sender,
clientSession.Key.SessionId));
}
else
{
fileTransferItem.Update(clientSession.Value.TotalBytesSent,
clientSession.Value.TransferSpeed,
clientSession.Value.TotalBytesSent == clientSession.Key.FileLength);
}
}
}
}
In order for what you want, both classes need to derive from the same base class or interface. For instance, if you have a common interface called IFileTransferSessions, then the following code should work:
IFileTransferSessions fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost : fileTransferSessionsAsClient;
or if you really want to keep the var syntax:
var fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost as IFileTransferSessions : fileTransferSessionsAsClient;
Note, you only need to cast the first tertiary result to the interface, or you can do both.
The var keyword is not like Variant from VB where it doesn't care what the type is at compile time. (that's closer to dynamic in C#) All it does is derive the type from the following usage. For two different classes to be derived, they must share a common base class or interface, and even then var needs to know about that base definition to work properly.
There are a couple different ways to solve this. Using interfaces would be the safest and most reasonable approach (or using a base class). They implement the same properties so they could both have an interface that exposes those properties then you could cast them to the interface.
If you cannot (or willnot) modify the class definitions to use interfaces then you can also use reflection or dynamic. These are both suseptible to runtime-errors which is worse then compile-time that you would get by using interfaces. Using dynamic has a little cleaner syntax and be easier to write than reflection. Just cast both items to dynamic and store them in a dynamic reference. Then you can call the necessary properties on them.
dynamic fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ?
(dynamic)fileTransferSessionsAsHost :
(dynamic)fileTransferSessionsAsClient;
Information on dynamic typing: http://msdn.microsoft.com/en-us/library/dd264736.aspx
Consider this code.
Dictionary<int, string> d1 = new Dictionary<int, string>();
Dictionary<int, string> d2 = new Dictionary<int, string>();
bool flag = true;
var d = flag ? d1 : d2;
It works, as the types of d1 and d2 match (or there is a cast from one to another). This is the key. If the types of the values returned by the ternary operator differ, it cannot infer the return type of the operator and that is the problem.
Actually you could explicitly cast one or both of the operands to a common interface (if there is one) to make it work.
If you can at least derive both hostSession and clientSession from the same base class or interface, then you can greatly reduce the code by factoring some of it out:
public void UpdateFileTransferItems(FileTransferItem.FileTransferRole role)
{
if (role == FileTransferItem.FileTransferRole.Sender)
{
foreach (var hostSession in fileTransferSessionsAsHost)
{
UpdateTransfers(hostSession);
}
}
else
{
foreach (var clientSession in fileTransferSessionsAsClient)
{
UpdateTransfers(clientSession);
}
}
}
private void UpdateTransfers(SessionBaseType session)
{
var fileTransferItem = activeFileTransfers.FirstOrDefault(fti => fti.SessionId == session.Key.SessionId);
if (fileTransferItem == null)
{
activeFileTransfers.Add(new FileTransferItem(session.Key.FileName,
session.Key.FileExtension,
session.Key.FileLength,
FileTransferItem.FileTransferRole.Sender,
session.Key.SessionId));
}
else
{
fileTransferItem.Update(session.Value.TotalBytesSent,
session.Value.TransferSpeed,
session.Value.TotalBytesSent == session.Key.FileLength);
}
}
If you can't modify the session classes to have a common ancestor, then the other approach would be to make a wrapper class that exposes the necessary properties, and you could still essentially use the above code except that instead of UpdateTransfers(clientSession);, you'd have UpdateTransfers(new SessionWrapper(clientSession));.

C# cast a class to an Interface List

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);
}

Best practices to scan all classes and methods for custom attribute

For the first time ever I've actually needed to do assembly scanning myself manually. I came across C# - how enumerate all classes with custom class attribute? which set me up with
var typesWithMyAttribute =
(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
let attributes = type.GetCustomAttributes(typeof(SomeAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = type, Attributes = attributes.Cast<SomeAttribute>() })
.ToList();
Which was simple enough to expand out to the method level
var methodsWithAttributes =
(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from method in type.GetMethods()
let attributes = method.GetCustomAttributes(typeof(SomeAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = type, Method = method,
Attributes = attributes.Cast<SomeAttribute>() })
.ToList();
Should I try to combine these 2 to do this in a single scan, or is that just falling into early optimization? (the scanning will only execute on app start)
Is there something different that would be more optimal to do for the scanning of the methods since there are far more methods than types in assemblies?
Reflection is very slow...
I think you've go the basics there. I'd recommend you change your code slightly to avoid the extra full scan taking place.
If you have to do this more than once, I'd also recommend you consider caching the results for whatever period of time is appropriate.
Sorta like this pseudo-code:
... (optional caches) ...
IDictionary<Type, IEnumerable<Attributes>> typeAttributeCache = new ...
IDictionary<MethodInfo, IEnumerable<Attributes>> methodAttributeCache = new ...
... (in another method or class) ...
foreach assembly in GetAssemblies()
foreach type in assembly.GetTypes()
typeAttributes = typeAttributeCache.TryGet(...) // you know the correct syntax, trying to be brief
if (typeAttributes is null)
typeAttributes = type.GetCustomAttributes().OfType<TypeImLookingFor>();
typeAttributeCache[type] = typeAttributes;
foreach methodInfo in type.GetMethods()
methodAttributes = methodAttributeCache.TryGet(...) // same as above
if (methodAttributes is null)
methodAttributes = methodInfo.GetCustomAttributes().OfType<TypeImLookingFor>();
methodAttributeCache[type] = methodAttributes;
// do what you need to do
I think you can optimize this but it depends on how the attributes are placed on methods and types. If you know that all of your types and/or methods with special attribute are defined in particular assemblies you can scan only these assemblies.
Also you could define some methods, like:
- IEnumerable<Type> GetAllTypesFromAssemblyByAttribute<TAttribute>(Assembly assembly) where TAttribute : Attribute
- IEnumerable<MethodInfo> GetAllMethodsFromTypeByAttribute<TAttribute>(Type type) where TAttribute : Attribute
and use these methods in your main scanning method.
So your result scan method could look like:
private void ScanAndDoSmth<TAttribute>(IEnumerable<Assembly> assemblies)
where TAttribute : Attribute
{
var result =
from assembly in assemblies
from type in GetAllTypesFromAssemblyByAttribute<TAttribute>(assembly)
let attributes = type.GetCustomAttributes(typeof(TAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = type, Attributes = attributes.Cast<TAttribute>();
}

Using reflection to get all classes of certain base type in dll

I have a dll that contains a number of classes that all inherit from a CommandBase class. I'm trying to get instances of all of these classes (CommandA, CommandB, CommandC, etc...) using reflection in C# so that I can call a specific method on each one. Here is what I have so far:
//get assemblies in directory.
string folder = Path.Combine(HttpContext.Current.Server.MapPath("~/"), "bin");
var files = Directory.GetFiles(folder, "*.dll");
//load each assembly.
foreach (string file in files)
{
var assembly = Assembly.LoadFile(file);
if (assembly.FullName == "MyCommandProject")
{
foreach (var type in assembly.GetTypes())
{
if (!type.IsClass || type.IsNotPublic) continue;
if(type is CommandBase)
{
var command = Activator.CreateInstance(type) as CommandBase;
}
}
}
}
I'm having 2 issues. The 1st issue is that the line "if(type is CommandBase") gives the following warning:
The given expression is never of the provided type CommandBase.
The 2nd issue is that I can't figure out how to get an instance of the actual object (CommandA, CommandB, etc...), just converting it to CommandBase isn't enough.
This is the method I use to load up based on an interface.
private static List<T> GetInstances<T>()
{
return (from t in Assembly.GetExecutingAssembly().GetTypes()
where t.GetInterfaces().Contains(typeof (T)) && t.GetConstructor(Type.EmptyTypes) != null
select (T) Activator.CreateInstance(t)).ToList();
}
And here's the same function that pulls back based on base class.
private static IList<T> GetInstances<T>()
{
return (from t in Assembly.GetExecutingAssembly().GetTypes()
where t.BaseType == (typeof(T)) && t.GetConstructor(Type.EmptyTypes) != null
select (T)Activator.CreateInstance(t)).ToList();
}
Of course it would need to be modified slightly to point at the reference you're loading.
You must change
if(type is CommandBase)
to
if(type.IsSubclassOf(typeof(CommandBase)))
If the IsSubclassOf is the converse of IsAssignableFrom. That is, if t1.IsSubclassOf(t2) is true, then t2.IsAssignableFrom(t1) is also true.
Change type is CommandBase to typeof(CommandBase).IsAssignableFrom(type)
That's because your type variable is a Type, not a CommandBase.
You want
if(type == typeof(CommandBase))
(Thanks Greg for the correction)

How enumerate all classes with custom class attribute?

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);
}

Categories

Resources