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

}

var newExpr = Expression.New(ci, argExpressions); // create expression that represents call to specified ctor with the specified arguments.

_registeredTypes.Add(key, Expression.Lambda(newExpr, new[] { pExp }).Compile() as Func<object[], TType>); // compile expression to create delegate, and add function to dictionary

}

}

}

///<summary>

///Returns instance of registered type by key.

///</summary>

///<typeparam name="TType"></typeparam>

///<param name="key"></param>

///<param name="args"></param>

///<returns></returns>

public TType Create(TKey key, params object[] args)

{

Func<object[], TType> foo;

if (_registeredTypes.TryGetValue(key, out foo))

{

return (TType)foo(args);

}

throw new ArgumentException("No type registered for this key.");

}

}

Could be used like this:

public class TestClass

{

public TestClass(string parameter)

{

Console.Write(parameter);

}

}

public void TestMethod()

{

var factory = new GenericFactory<string, TestClass>(); factory.Register("key", typeof(string));

TestClass newInstance = factory.Create("key", "testParameter");

}

Using FormatterServices.GetUninitializedObject

T instance = (T)FormatterServices.GetUninitializedObject(typeof(T));

In case of using FormatterServices.GetUninitializedObject constructors and field initializers will not be called. It is meant to be used in serializers and remoting engines

Section 63.4: Get a Strongly-Typed Delegate to a Method or Property via Reflection

When performance is a concern, invoking a method via reflection (i.e. via the MethodInfo.Invoke method) is not ideal. However, it is relatively straightforward to obtain a more performant strongly-typed delegate using the

GoalKicker.com – C# Notes for Professionals

336

Delegate.CreateDelegate function. The performance penalty for using reflection is incurred only during the delegate-creation process. Once the delegate is created, there is little-to-no performance penalty for invoking it:

// Get a MethodInfo for the Math.Max(int, int) method...

var maxMethod = typeof(Math).GetMethod("Max", new Type[] { typeof(int), typeof(int) });

// Now get a strongly-typed delegate for Math.Max(int, int)...

var stronglyTypedDelegate = (Func<int, int, int>)Delegate.CreateDelegate(typeof(Func<int, int,

int>), null, maxMethod);

// Invoke the Math.Max(int, int) method using the strongly-typed delegate...

Console.WriteLine("Max of 3 and 5 is: {0}", stronglyTypedDelegate(3, 5));

This technique can be extended to properties as well. If we have a class named MyClass with an int property named MyIntProperty, the code to get a strongly-typed getter would be (the following example assumes 'target' is a valid instance of MyClass):

// Get a MethodInfo for the MyClass.MyIntProperty getter...

var theProperty = typeof(MyClass).GetProperty("MyIntProperty"); var theGetter = theProperty.GetGetMethod();

//Now get a strongly-typed delegate for MyIntProperty that can be executed against any MyClass instance...

var stronglyTypedGetter = (Func<MyClass, int>)Delegate.CreateDelegate(typeof(Func<MyClass, int>), theGetter);

//Invoke the MyIntProperty getter against MyClass instance 'target'...

Console.WriteLine("target.MyIntProperty is: {0}", stronglyTypedGetter(target));

...and the same can be done for the setter:

// Get a MethodInfo for the MyClass.MyIntProperty setter...

var theProperty = typeof(MyClass).GetProperty("MyIntProperty"); var theSetter = theProperty.GetSetMethod();

//Now get a strongly-typed delegate for MyIntProperty that can be executed against any MyClass instance...

var stronglyTypedSetter = (Action<MyClass, int>)Delegate.CreateDelegate(typeof(Action<MyClass, int>), theSetter);

//Set MyIntProperty to 5...

stronglyTypedSetter(target, 5);

Section 63.5: Get a generic method and invoke it

Let's say you have class with generic methods. And you need to call its functions with reflection.

public class Sample

{

public void GenericMethod<T>()

{

// ...

}

public static void StaticMethod<T>()

{

//...

}

}

Let's say we want to call the GenericMethod with type string.

Sample sample = new Sample();//or you can get an instance via reflection

GoalKicker.com – C# Notes for Professionals

337

MethodInfo method = typeof(Sample).GetMethod("GenericMethod"); MethodInfo generic = method.MakeGenericMethod(typeof(string));

generic.Invoke(sample, null);//Since there are no arguments, we are passing null

For the static method you do not need an instance. Therefore the first argument will also be null.

MethodInfo method = typeof(Sample).GetMethod("StaticMethod"); MethodInfo generic = method.MakeGenericMethod(typeof(string)); generic.Invoke(null, null);

Section 63.6: Get a System.Type

For an instance of a type:

var theString = "hello";

var theType = theString.GetType();

From the type itself:

var theType = typeof(string);

Section 63.7: Getting and setting properties

Basic usage:

PropertyInfo prop = myInstance.GetType().GetProperty("myProperty");

// get the value myInstance.myProperty object value = prop.GetValue(myInstance);

int newValue = 1;

// set the value myInstance.myProperty to newValue prop.setValue(myInstance, newValue);

Setting read-only automatically-implemented properties can be done through it's backing field (in .NET Framework name of backing field is "k__BackingField"):

// get backing field info

FieldInfo fieldInfo = myInstance.GetType()

.GetField("<myProperty>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);

int newValue = 1;

// set the value of myInstance.myProperty backing field to newValue fieldInfo.SetValue(myInstance, newValue);

Section 63.8: Create an instance of a Generic Type and invoke it's method

var baseType = typeof(List<>);

var genericType = baseType.MakeGenericType(typeof(String)); var instance = Activator.CreateInstance(genericType);

var method = genericType.GetMethod("GetHashCode");

var result = method.Invoke(instance, new object[] { });

GoalKicker.com – C# Notes for Professionals

338

Section 63.9: Custom Attributes

Find properties with a custom attribute - MyAttribute

var props = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(

prop => Attribute.IsDefined(prop, typeof(MyAttribute)));

Find all custom attributes on a given property

var attributes = typeof(t).GetProperty("Name").GetCustomAttributes(false);

Enumerate all classes with custom attribute - MyAttribute

static IEnumerable<Type> GetTypesWithAttribute(Assembly assembly) { foreach(Type type in assembly.GetTypes()) {

if (type.GetCustomAttributes(typeof(MyAttribute), true).Length > 0) { yield return type;

}

}

}

Read value of a custom attribute at runtime

public static class AttributeExtensions

{

///<summary>

///Returns the value of a member attribute for any member in a class.

///(a member is a Field, Property, Method, etc...)

///<remarks>

///If there is more than one member of the same name in the class, it will return the first one (this applies to overloaded methods)

///</remarks>

///<example>

///Read System.ComponentModel Description Attribute from method 'MyMethodName' in class

'MyClass':

///var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) => d.Description);

///</example>

///<param name="type">The class that contains the member as a type</param>

///<param name="MemberName">Name of the member in the class</param>

///<param name="valueSelector">Attribute type and property to get (will return first instance if there are multiple attributes of the same type)</param>

///<param name="inherit">true to search this member's inheritance chain to find the attributes; otherwise, false. This parameter is ignored for properties and events</param>

///</summary>

public static TValue GetAttribute<TAttribute, TValue>(this Type type, string MemberName, Func<TAttribute, TValue> valueSelector, bool inherit = false) where TAttribute : Attribute

{

var att = type.GetMember(MemberName).FirstOrDefault().GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault() as TAttribute;

if (att != null)

{

return valueSelector(att);

}

return default(TValue);

}

GoalKicker.com – C# Notes for Professionals

339