Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

}

Usage

//Read System.ComponentModel Description Attribute from method 'MyMethodName' in class 'MyClass' var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) => d.Description);

Section 63.10: Instantiating classes that implement an interface (e.g. plugin activation)

If you want your application to support a plug-in system, for example to load plug-ins from assemblies located in plugins folder:

interface IPlugin

{

string PluginDescription { get; } void DoWork();

}

This class would be located in a separate dll

class HelloPlugin : IPlugin

{

public string PluginDescription => "A plugin that says Hello"; public void DoWork()

{

Console.WriteLine("Hello");

}

}

Your application's plugin loader would find the dll files, get all types in those assemblies that implement IPlugin, and create instances of those.

public IEnumerable<IPlugin> InstantiatePlugins(string directory)

{

var pluginAssemblyNames = Directory.GetFiles(directory, "*.addin.dll").Select(name => new FileInfo(name).FullName).ToArray();

//load the assemblies into the current AppDomain, so we can instantiate the types later foreach (var fileName in pluginAssemblyNames)

AppDomain.CurrentDomain.Load(File.ReadAllBytes(fileName));

var assemblies = pluginAssemblyNames.Select(System.Reflection.Assembly.LoadFile); var typesInAssembly = assemblies.SelectMany(asm => asm.GetTypes());

var pluginTypes = typesInAssembly.Where(type => typeof (IPlugin).IsAssignableFrom(type)); return pluginTypes.Select(Activator.CreateInstance).Cast<IPlugin>();

}

Section 63.11: Get a Type by name with namespace

To do this you need a reference to the assembly which contains the type. If you have another type available which you know is in the same assembly as the one you want you can do this:

typeof(KnownType).Assembly.GetType(typeName);

where typeName is the name of the type you are looking for (including the namespace) , and KnownType is the type you know is in the same assembly.

GoalKicker.com – C# Notes for Professionals

340

Less e cient but more general is as follows:

Type t = null;

foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())

{

if (ass.FullName.StartsWith("System.")) continue;

t = ass.GetType(typeName); if (t != null)

break;

}

Notice the check to exclude scanning System namespace assemblies to speed up the search. If your type may actually be a CLR type, you will have to delete these two lines.

If you happen to have the fully assembly-qualified type name including the assembly you can simply get it with

Type.GetType(fullyQualifiedName);

Section 63.12: Determining generic arguments of instances of generic types

If you have an instance of a generic type but for some reason don't know the specific type, you might want to determine the generic arguments that were used to create this instance.

Let's say someone created an instance of List<T> like that and passes it to a method:

var myList = new List<int>(); ShowGenericArguments(myList);

where ShowGenericArguments has this signature:

public void ShowGenericArguments(object o)

so at compile time you don't have any idea what generic arguments have been used to create o. Reflection provides a lot of methods to inspect generic types. At first, we can determine if the type of o is a generic type at all:

public void ShowGenericArguments(object o)

{

if (o == null) return;

Type t = o.GetType();

if (!t.IsGenericType) return;

...

Type.IsGenericType returns true if the type is a generic type and false if not.

But this is not all we want to know. List<> itself is a generic type, too. But we only want to examine instances of specific constructed generic types. A constructed generic type is for example a List<int> that has a specific type argument for all its generic parameters.

The Type class provides two more properties, IsConstructedGenericType and IsGenericTypeDefinition, to distinguish these constructed generic types from generic type definitions:

typeof(List<>).IsGenericType // true typeof(List<>).IsGenericTypeDefinition // true

GoalKicker.com – C# Notes for Professionals

341

typeof(List<>).IsConstructedGenericType// false

typeof(List<int>).IsGenericType // true typeof(List<int>).IsGenericTypeDefinition // false typeof(List<int>).IsConstructedGenericType// true

To enumerate the generic arguments of an instance, we can use the GetGenericArguments() method that returns an Type array containing the generic type arguments:

public void ShowGenericArguments(object o)

{

if (o == null) return; Type t = o.GetType();

if (!t.IsConstructedGenericType) return;

foreach(Type genericTypeArgument in t.GetGenericArguments()) Console.WriteLine(genericTypeArgument.Name);

}

So the call from above (ShowGenericArguments(myList)) results in this output:

Int32

Section 63.13: Looping through all the properties of a class

Type type = obj.GetType();

//To restrict return properties. If all properties are required don't provide flag.

BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; PropertyInfo[] properties = type.GetProperties(flags);

foreach (PropertyInfo property in properties)

{

Console.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(obj, null));

}

GoalKicker.com – C# Notes for Professionals

342