Generally, when people talk about reflection, the main concern is the performance. Because it runs on runtime, so theoretically, it is a little bit slower than the normal application. But it is flexible for many scenarios, especially if you develop the framework. If it is acceptable to spend a few seconds (or only hundreds of milliseconds) to load assemblies, then feel free to use it.
Let’s walk through an example; We are going to use an interface called “ISpeaker”.
internal interface ISpeaker
{
string SayHello();
}
Create three implementation classes:
English Speakers
internal class EnglishSpeaker : ISpeaker
{
public string Name => this.GetType().ToString();
public string SayHello()
{
return "Hello!";
}
}
Urdu Speakers
internal class UrduSpeaker : ISpeaker
{
public string Name => this.GetType().ToString();
public string SayHello()
{
return "as-salaam-alaikum";
}
}
Chinese Speakers
internal class ChineseSpeaker : ISpeaker
{
public string Name => this.GetType().ToString();
public string SayHello()
{
return "Nihao";
}
}
Now we can use reflection to find all the implementations of ISpeaker
interface and call their methods or properties.
internal class ReflectionHelper
{
public static List<Type> GetAvailableSpeakers()
{
// You can also use AppDomain.CurrentDomain.GetAssemblies() to load all assemblies in the current domain.
// Get the specified assembly.
var assembly =
Assembly.LoadFrom(Path.Combine(Directory.GetCurrentDirectory(), "ReflectionDemo.dll"));
// Find all the types in the assembly.
var types = assembly.GetTypes();
// Apply the filter to find the implementations of ISayHello interface.
var result = types.Where(x => x.IsClass && typeof(ISpeaker).IsAssignableFrom(x)).ToList();
// Or you can use types.Where(x => x.IsClass && x.GetInterfaces().Contains(typeof(ISpeaker))).ToList();
return result;
}
}
In this class, we load the specified dll file that contains types we need. Then we can apply the LINQ query to find all the implementations of ISpeaker
interface using Reflection.
Test the program output. we can output the name and call SayHello
method of each speaker:
using ReflectionDemo;
using System.Reflection;
Console.WriteLine("Hello, World!");
Console.WriteLine("Here is the Reflection sample:");
// Find all the speakers in the current domain
var availableSpeakers = ReflectionHelper.GetAvailableSpeakers();
foreach (var availableSpeaker in availableSpeakers)
{
// Create the instance of the type
var speaker = Activator.CreateInstance(availableSpeaker);
// Get the property info of the given property name
PropertyInfo namePropertyInfo = availableSpeaker.GetProperty("Name");
// Then you can get the value of the property
var name = namePropertyInfo?.GetValue(speaker)?.ToString();
Console.WriteLine($"I am {name}");
// Invoke the method of the instance
Console.WriteLine(availableSpeaker.InvokeMember("SayHello", BindingFlags.InvokeMethod, null, speaker, null));
}
Console.WriteLine();
Console.ReadKey();
Run the program, you will see the below output:
If we need to add other speakers in other languages, just add the implementation classes in the same project. .NET reflection can automatically find out all the required classes and call the methods correctly.
It is extremely useful when we create the plugin-type applications. First we make the interfaces and call the methods from the client by reflection. Then we can create plugins following the interface for the client, which can be loaded as the *.dll files dynamically and executed.
Another scenario is for the framework development. As a framework developer, you will not be able to know what implementations the users will create, so you can only use reflection to create these instances. One example is in some MVVM frameworks, if you create the classes following the conventions, eg. xxxViewModel, the framework can find all the ViewModels and load them automatically using reflection.
The main namespaces we need to use for reflection are System.Reflection and System.Type. You may also need to know the below terms:
- Assembly
- Module
- ConstructorInfo
- MethodInfo
- FieldInfo
- EventInfo
- PropertyInfo
- ParameterInfo
- CustomAttributeData
Resources
Dynamically Loading and Using Types
https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support
Add to favorites