Type loader
// this class is documented here:
// http://blog.thekieners.com/2010/09/06/type-gettype-implementation-with-help-of-xamlreader/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
namespace Nova.Core.Common
{
/// <summary>
/// Provides functionality to load any type with its class name, namespace and assembly-name within the Silverlight environment.
/// </summary>
/// <remarks>
/// The Type.GetType method is different in Silverlight than in the standard .NET runtime. In Silverlight we have to provide the
/// fully qualified assembly name to get a type in a custom assembly. Only build in controls or types in the same assembly are
/// excluded from this rule. Full qualified assembly name means a syntax like the following:
/// MyComponent.MyType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4bec85d7bec6698f.
/// This class uses the XamlReader capability to resolve type during parsing a xaml-string. While this is a little time consuming
/// the TypeLoader maintains a cache to get types faster.
/// </remarks>
public static class TypeLoader
{
// cache for resolved type
private static readonly Dictionary<string, Type> _cache = new Dictionary<string, Type>();
/// <summary>
/// Gets the System.Type with the specified name, name space and assembly name.
/// </summary>
/// <param name="className">The class name without namespace.</param>
/// <param name="nameSpace">The name space</param>
/// <param name="assemblyName">The name of the assembly containing the type.</param>
/// <returns>The type matching the provided parameters or null if not found.</returns>
//[DebuggerStepThrough()]
public static Type GetType(string className, string nameSpace, string assemblyName)
{
// check
if (StringHelper.IsNullOrWhiteSpace(nameSpace))
return null;
string xamlNamespace = string.Format("clr-namespace:{0}", nameSpace);
// assembly name is optional
if (!StringHelper.IsNullOrWhiteSpace(assemblyName))
xamlNamespace += string.Format(";assembly={0}", assemblyName);
return GetType(className, xamlNamespace);
}
/// <summary>
/// Gets the System.Type with the specified name.
/// This method overload can be used for:
/// 1. core controls such as Button, Grid, ListBox, etc. without specifying the namespace or assembly name.
/// 2. with the qualified assembly name of the type without version and public key token like this: "MyNamespace.MyType, MyAssembly".
/// </summary>
/// <param name="className">Pure class name of Core Controls such as Button, Grid, ListBox, etc.</param>
/// <returns>The type matching the provided parameters or null if not found.</returns>
//[DebuggerStepThrough()]
public static Type GetType(string className)
{
if (className != null && className.Contains(","))
{
string[] qualifiedNameParts = className.Split(',');
if (qualifiedNameParts.Length == 2)
{
string[] fullClassNameParts = qualifiedNameParts[0].Split('.');
if (fullClassNameParts.Length > 0)
{
// classname
string newClassName = fullClassNameParts.Last().Trim();
// namespace
string nameSpace = "";
for (int i = 0; i < fullClassNameParts.Length - 1; i++)
{
nameSpace += fullClassNameParts[i] + ".";
}
nameSpace = nameSpace.TrimEnd('.');
string assemblyName = qualifiedNameParts[1].Trim();
return GetType(newClassName, nameSpace, assemblyName);
}
}
}
return GetType(className, "");
}
/// <summary>
/// Gets the System.Type with the specified name. The xaml namespace specifies the namespace and assembly name in the same syntax as in xaml.
/// </summary>
/// <param name="className">The class name without namespace.</param>
/// <param name="xamlNamespace">
/// The xaml namespace. This is the same syntax as used in XAML syntax.
/// Example: "clr-namespace:MyComponent.SubNamespace;assembly=MyAssemblyName
/// </param>
/// <returns>The type matching the provided parameters or null if not found.</returns>
//[DebuggerStepThrough()]
public static Type GetType(string className, string xamlNamespace)
{
// check input
if (StringHelper.IsNullOrWhiteSpace(className))
return null;
if (className.Contains("."))
throw new ArgumentException(
"className must not include the namespace. Please provide namespace with separate parameter.");
// check if type is already in cache
string key = xamlNamespace + "&" + className;
if (_cache.ContainsKey(key))
return _cache[key];
lock (_cache)
{
try
{
// check again because another thread might be faster and has already created the cache-entry
if (_cache.ContainsKey(key))
return _cache[key];
// create xaml with a simply Style element and set the TargetType property with the provided type name
string xaml = "<Style xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ";
// set the xaml namesapce if provided
if (!StringHelper.IsNullOrWhiteSpace(xamlNamespace))
{
xaml += string.Format("xmlns:tmp='{0}' TargetType='tmp:{1}' />", xamlNamespace, className);
}
else
{
// Core controls such as Button, Grid, ListBox, etc do not need a namespace
xaml += string.Format("TargetType='{0}' />", className);
}
// let the XamlParser load the type via the TargetType property
var style = XamlReader.Load(xaml) as Style;
if (style != null)
{
Type targetType = style.TargetType;
AddToCache(key, targetType);
return targetType;
}
}
catch (Exception ex)
{
// Try to load type in executing assembly
if (!StringHelper.IsNullOrWhiteSpace(xamlNamespace))
{
// note: Type.GetType uses needs assembly-qualified name of the type to get. If the type is
// in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply
// the type name qualified by its namespace.
Type type =
Type.GetType(string.Format("{0}.{1}",
xamlNamespace.Replace("clr-namespace:", "").TrimEnd(';'),
className));
if (type != null)
{
// add to cache
AddToCache(key, type);
return type;
}
}
//****** DONT SET VALUE TO NULL, BECAUSE OF CASES WHEN AN ASSEMBLY IS *****
//****** LOADED DYNAMICALLY INTO THE APPLICATION DOMAIN *****
// don't let the exception repeat. Set null as cache value
AddToCache(key, null);
//**************************************************************************/
}
}
return null;
}
private static void AddToCache(string key, Type type)
{
_cache.Add(key, type);
CompositionTarget.Rendering -= CompositionTarget_Rendering;
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
private static void CompositionTarget_Rendering(object sender, EventArgs e)
{
CompositionTarget.Rendering -= CompositionTarget_Rendering;
_cache.Clear();
}
#region Nested type: StringHelper
private static class StringHelper
{
// helper because .NET 3.5 does not support IsNullOrWhiteSpace
public static bool IsNullOrWhiteSpace(string str)
{
if (str == null)
return true;
if (str.Trim() == string.Empty)
return true;
return false;
}
}
#endregion
}
}
Related examples in the same category
1. | Call GetType() from StringBuilder | | |
2. | Call GetType for int data type | | |
3. | IsGeneric and IsGenericTypeDefinition | | |
4. | demonstrates both the instance and static GetType methods | | |
5. | Generic methods, like nongeneric methods, can be invoked dynamically at run time. | | |
6. | Type.GetGenericArguments and MethodInfo.GetGenericArguments: | | |
7. | Get Generic Type Definition | | |
8. | Query properties of a Type | | |
9. | Deeper Reflection:Listing All the Types in an Assembly | | |
10. | Illustrates runtime type creation | | |
11. | The typeName parameter is a combination of the Assembly and Type names | | |
12. | Call static method GetType from Type to get the Type instance | | |
13. | Use GetCustomAttributes from Type to get custom attributes | | |
14. | Use Type.GetType to check the type of an object | | |
15. | Get object Type Name, UnderlyingSystemType, IsClass | | |
16. | Type.GetConstructors | | |
17. | Use Type.IsClass to check if a type is a class | | |
18. | Print Types | | |
19. | Determining the base classes and interfaces for a class. | | |
20. | Create Object from assembly name and class name | | |
21. | Makes a shallow copy of the object to a different class type (inherits from the original) | | |
22. | Makes a shallow copy of the object | | |
23. | Get all methods from an object | | |
24. | Get Derivation from an object | | |
25. | The full name of the Array type | | |
26. | Change type | | |
27. | Does a given Type have a Default Constructor | | |
28. | Is it a Nullable Type | | |
29. | Is Value Type Unitialized Value | | |
30. | Get Type Unitialized Value | | |
31. | Is Object Unitialized Value | | |
32. | Is it a SubClass for another class | | |
33. | Convert type from initial Value | | |
34. | Returns all assemblies and their properties | | |
35. | Helper to display the "contents" of the Value Object | | |
36. | Get a public field value given its name | | |
37. | Deep Comparison two objects if they are alike. | | |
38. | Set the specified public field value of an object | | |
39. | Determine if a type is cloneable: either a value type or implementing ICloneable. | | |
40. | Provides a simple reflection based mapper to perform a Data Mapping between two types of objects | | |
41. | Represents type declarations: class types, interface types, array types, value types, enumeration types, type parameters, generic type definitions, and open or closed constructed generic types. | | |
42. | Gets the attributes associated with the Type. | | |
43. | Gets the type from which the current Type directly inherits. | | |
44. | Gets a value indicating whether the current Type object has type parameters that have not been replaced by specific types. | | |
45. | Gets the type that declares the current nested type or generic type parameter. | | |
46. | Gets a reference to the default binder. | | |
47. | Represents the member filter used on attributes. | | |
48. | Returns an array of Type objects representing a filtered list of interfaces implemented or inherited by the current Type. | | |
49. | Returns a filtered array of MemberInfo objects of the specified member type. | | |
50. | Gets the number of dimensions in an Array. | | |
51. | Searches for the members defined for the current Type whose DefaultMemberAttribute is set. | | |
52. | Type.GetElementType | | |
53. | Returns a Type object that represents a generic type definition from which the current generic type can be constructed. | | |
54. | Searches for the interface with the specified name. | | |
55. | Get types implementing Dictionary | | |
56. | Returns all the public properties of the current Type. | | |
57. | Type to string | | |
58. | Get Full Type String | | |
59. | Get class members | | |
60. | Reflector | | |
61. | Is Type a primitive type | | |
62. | Find Method With One Parameter Of Type | | |
63. | Determines whether the current type is an implementation of the specified interface. | | |
64. | Returns equality with type conversion | | |
65. | Groups the utility methods that extracts the meta data of a type. | | |
66. | Get Friendly Type Name | | |
67. | Recursively gets all generic type params in any given type definition. | | |
68. | Type Manager | | |
69. | Given an anonymous type | | |
70. | Type Normalizer | | |
71. | Run static/Instance method | | |
72. | Get Subclass | | |