ReflectionisaC#languagemechanismforaccessingdynamicobjectpropertiesonruntime.Typically,reflectionis used to fetch the information about dynamic object type and object attribute values. In REST application, for example, reflection could be used to iterate through serialized response object.
Remark:AccordingtoMSguidelinesperformancecriticalcodeshouldavoidreflection.See https://msdn.microsoft.com/en-us/library/ff647790.aspx
Section63.1: Get the members of a type
usingSystem;
usingSystem.Reflection;
usingSystem.Linq;
publicclassProgram
{
publicstaticvoidMain()
{
varmembers=typeof(object)
.GetMembers(BindingFlags.Public|
BindingFlags.Static|
BindingFlags.Instance);
foreach(varmemberinmembers)
{
boolinherited=member.DeclaringType.Equals(typeof(object).Name);
Console.WriteLine($”{member.Name}isa{member.MemberType},”+
$”ithas{(inherited?””:”not”)}beeninherited.”);
}
}
}
Output(seenoteaboutoutputorderfurtherdown):
GetType is a Method, it has not been inherited. GetHashCode is a Method, it has not been inherited. ToString is a Method, it has not been inherited. Equals is a Method, it has not been inherited. Equals is a Method, it has not been inherited. ReferenceEquals is a Method, it has not been inherited. .ctor is a Constructor, it has not been inherited.
WecanalsousetheGetMembers()withoutpassinganyBindingFlags.Thiswillreturnallpublicmembersofthat specific type.
OnethingtonotethatGetMembersdoesnotreturnthemembersinanyparticularorder,soneverrelyontheorder that GetMembersreturns you.
ViewDemo
Section63.2:Getamethodandinvokeit
GetInstancemethodandinvokeit
usingSystem;
publicclassProgram
{
publicstaticvoidMain()
{
vartheString=”hello”;
varmethod=theString
.GetType()
.GetMethod(“Substring”,
new[]{typeof(int),typeof(int)});//Thetypesofthemethod
arguments
varresult=method.Invoke(theString,newobject[]{0,4}); Console.WriteLine(result);
}
}
Output:
hell
ViewDemo
GetStaticmethodandinvokeit
On the otherhand, if themethod isstatic, you donot needan instance tocall it.
varmethod=typeof(Math).GetMethod(“Exp”);
varresult=method.Invoke(null,newobject[]{2});//Passnullasthefirstargument(noneedforan instance)
Console.WriteLine(result);//You’llgete^2
Output:
7.38905609893065
ViewDemo
Section63.3:CreatinganinstanceofaType
ThesimplestwayistousetheActivatorclass.
However,eventhoughActivatorperformancehavebeenimprovedsince.NET3.5,using
Activator.CreateInstance()isbadoptionsometimes,dueto(relatively)lowperformance:Test1,Test2,Test3…
Typetype=typeof(BigInteger);
objectresult=Activator.CreateInstance(type);//Requiresparameterlessconstructor.
Console.WriteLine(result);//Output:0
result=Activator.CreateInstance(type,123);//Requiresaconstructorwhichcanreceivean‘int’compatibleargument.
Console.WriteLine(result);//Output:123
WithActivatorclass
YoucanpassanobjectarraytoActivator.CreateInstanceifyouhavemorethanoneparameter.
//WithaconstructorsuchasMyClass(int,int,string)
Activator.CreateInstance(typeof(MyClass),newobject[]{1,2,”HelloWorld”});
Typetype=typeof(someObject);
varinstance=Activator.CreateInstance(type);
Foragenerictype
The MakeGenericTypemethod turns an open generic type (like List<>) into a concrete type (like List<string>) by applyingtypeargumentstoit.
//genericListwithnoparameters
TypeopenType=typeof(List<>);
//TocreateaList<string>
Type[]tArgs={typeof(string)};
Typetarget=openType.MakeGenericType(tArgs);
//Createaninstance-Activator.CreateInstancewillcallthedefaultconstructor.
//ThisisequivalenttocallingnewList<string>().
List<string>result=(List<string>)Activator.CreateInstance(target);
TheList<>syntaxisnotpermittedoutsideofatypeofexpression.
WithoutActivatorclass
Usingnewkeyword(willdoforparameterlessconstructors)
TGetInstance<T>()whereT:new()
{
Tinstance=newT(); returninstance;
}
UsingInvokemethod
//Gettheinstanceofthedesiredconstructor(hereittakesastringasaparameter).
ConstructorInfoc=typeof(T).GetConstructor(new[]{typeof(string)});
//Don’tforgettocheckifsuchconstructorexists
if(c==null)
thrownewInvalidOperationException(string.Format(“Aconstructorfortype'{0}’wasnot found.”,typeof(T)));
Tinstance=(T)c.Invoke(newobject[]{“test”})
UsingExpressiontrees
Expressiontreesrepresentcodeinatree-likedatastructure,whereeachnodeisanexpression.AsMSDNexplains:
Expression is a sequence of one or more operands and zero or more operators that can be evaluated to a single value, object, method, or namespace. Expressions can consist of a literal value, a method invocation, an operator and its operands, or a simple name. Simple names can be the name of a variable, type member, method parameter, namespace or type.
publicclassGenericFactory<TKey,TType>
{
privatereadonlyDictionary<TKey,Func<object[],TType>>_registeredTypes;//dictionary, thatholdsconstructorfunctions.
privateobject_locker=newobject();//objectforlockingdictionary,toguaranteethread
safety
publicGenericFactory()
{
_registeredTypes=newDictionary<TKey,Func<object[],TType>>();
}
///<summary>
///Findandregistersuitableconstructorfortype
///</summary>
///<typeparamname=”TType”></typeparam>
///<paramname=”key”>Keyforthisconstructor</param>
///<paramname=”parameters”>Parameters</param>
publicvoidRegister(TKeykey,paramsType[]parameters)
{
ConstructorInfoci=typeof(TType).GetConstructor(BindingFlags.Public| BindingFlags.Instance,null,CallingConventions.HasThis,parameters,newParameterModifier[]{});
//Gettheinstanceofctor.
if(ci==null)
thrownewInvalidOperationException(string.Format(“Constructorfortype'{0}’was notfound.”,typeof(TType)));
Func<object[],TType>ctor;
lock(_locker)
{
beenregistered
if(!_registeredTypes.TryGetValue(key,outctor))//checkifsuchctoralready
{
varpExp=Expression.Parameter(typeof(object[]),”arguments”);//create
parameterExpression
varctorParams=ci.GetParameters();//getparameterinfofromconstructor
varargExpressions=newExpression[ctorParams.Length];//arraythatwill containsparameterexpessions
for(vari=0;i<parameters.Length;i++)
{
varindexedAcccess=Expression.ArrayIndex(pExp,Expression.Constant(i)); if(!parameters[i].IsClass&&!parameters[i].IsInterface)//check if
parameterisavaluetype
{
varlocalVariable=Expression.Variable(parameters[i], “localVariable”);//ifso-weshouldcreatelocalvariablethatwillstoreparaametervalue
Expression.Constant(null)),
varblock=Expression.Block(new[]{localVariable},
Expression.IfThenElse(Expression.Equal(indexedAcccess,
Expression.Assign(localVariable,
Expression.Default(parameters[i])),
Expression.Assign(localVariable,
Expression.Convert(indexedAcccess,parameters[i]))
),
localVariable
);
argExpressions[i]=block;
}
else
argExpressions[i]=Expression.Convert(indexedAcccess,parameters[i]);
}
var newExpr = Expression.New(ci, argExpressions); // create expression that representscalltospecifiedctorwiththespecifiedarguments.
_registeredTypes.Add(key,Expression.Lambda(newExpr,new[]{pExp}).Compile() as Func<object[], TType>); // compile expression to create delegate, and add function to dictionary
}
}
}
///<summary>
///Returnsinstanceofregisteredtypebykey.
///</summary>
///<typeparamname=”TType”></typeparam>
///<paramname=”key”></param>
///<paramname=”args”></param>
///<returns></returns>
publicTTypeCreate(TKey key,paramsobject[]args)
{
Func<object[],TType>foo;
if(_registeredTypes.TryGetValue(key,outfoo))
{
return(TType)foo(args);
}
thrownewArgumentException(“Notyperegisteredforthiskey.”);
}
}
Couldbeusedlikethis:
publicclassTestClass
{
publicTestClass(stringparameter)
{
Console.Write(parameter);
}
}
publicvoidTestMethod()
{
varfactory=newGenericFactory<string,TestClass>();
factory.Register(“key”,typeof(string));
TestClassnewInstance=factory.Create(“key”,”testParameter”);
}
UsingFormatterServices.GetUninitializedObject
Tinstance=(T)FormatterServices.GetUninitializedObject(typeof(T));
IncaseofusingFormatterServices.GetUninitializedObjectconstructorsandfieldinitializerswillnotbecalled.It ismeanttobeusedinserializersandremotingengines
Section63.4:GetaStrongly-TypedDelegatetoaMethodor Property via Reflection
When performance is a concern, invoking a method via reflection (i.e. via the MethodInfo.Invokemethod) is not ideal. However, it is relatively straightforward to obtain a more performant strongly-typed delegate using the
Delegate.CreateDelegatefunction.Theperformancepenaltyforusingreflectionisincurredonlyduringthe delegate-creation process. Once the delegate is created, there is little-to-no performance penalty for invoking it:
//GetaMethodInfofortheMath.Max(int,int)method…
varmaxMethod=typeof(Math).GetMethod(“Max”,newType[]{typeof(int),typeof(int)});
//Nowgetastrongly-typeddelegateforMath.Max(int,int)…
varstronglyTypedDelegate=(Func<int,int,int>)Delegate.CreateDelegate(typeof(Func<int,int, int>),null,maxMethod);
//InvoketheMath.Max(int,int)methodusingthestrongly-typeddelegate…
Console.WriteLine(“Maxof3and5is:{0}”,stronglyTypedDelegate(3,5));
Thistechniquecanbeextendedtopropertiesaswell.IfwehaveaclassnamedMyClasswithanintproperty namedMyIntProperty,thecodetogetastrongly-typedgetterwouldbe(thefollowingexampleassumes’target’is a valid instance of MyClass):
//GetaMethodInfofortheMyClass.MyIntPropertygetter…
vartheProperty=typeof(MyClass).GetProperty(“MyIntProperty”);
vartheGetter=theProperty.GetGetMethod();
//Nowgetastrongly-typeddelegateforMyIntPropertythatcanbeexecutedagainstanyMyClass instance…
varstronglyTypedGetter=(Func<MyClass,int>)Delegate.CreateDelegate(typeof(Func<MyClass,int>), theGetter);
//InvoketheMyIntPropertygetteragainstMyClassinstance‘target’…
Console.WriteLine(“target.MyIntPropertyis:{0}”,stronglyTypedGetter(target));
…andthesamecanbedoneforthe setter:
//GetaMethodInfofortheMyClass.MyIntPropertysetter…
vartheProperty=typeof(MyClass).GetProperty(“MyIntProperty”);
vartheSetter=theProperty.GetSetMethod();
//Nowgetastrongly-typeddelegateforMyIntPropertythatcanbeexecutedagainstanyMyClass instance…
varstronglyTypedSetter=(Action<MyClass,int>)Delegate.CreateDelegate(typeof(Action<MyClass, int>),theSetter);
//SetMyIntPropertyto5…
stronglyTypedSetter(target,5);
Section63.5:Getagenericmethodandinvokeit
Let’ssayyouhaveclasswithgenericmethods.Andyouneedtocallitsfunctionswithreflection.
publicclassSample
{
publicvoidGenericMethod<T>()
{
//…
}
publicstaticvoidStaticMethod<T>()
{
//…
}
}
Let’ssaywewanttocalltheGenericMethodwithtypestring.
Samplesample=newSample();//oryoucangetaninstanceviareflection
MethodInfo method = typeof(Sample).GetMethod(“GenericMethod”); MethodInfogeneric=method.MakeGenericMethod(typeof(string));
generic.Invoke(sample,null);//Sincetherearenoarguments,wearepassingnull
Forthestaticmethodyoudonotneedaninstance.Thereforethefirstargumentwillalsobenull.
MethodInfomethod=typeof(Sample).GetMethod(“StaticMethod”); MethodInfogeneric=method.MakeGenericMethod(typeof(string));
generic.Invoke(null,null);
Foraninstanceofatype:
vartheString=”hello”;
vartheType=theString.GetType();
From thetype itself:
vartheType=typeof(string);
Section63.7:Gettingandsettingproperties
Basicusage:
PropertyInfoprop=myInstance.GetType().GetProperty(“myProperty”);
//getthevaluemyInstance.myProperty
objectvalue=prop.GetValue(myInstance);
intnewValue=1;
//setthevaluemyInstance.myPropertytonewValue
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 “kBackingField”):
//getbackingfieldinfo
FieldInfofieldInfo=myInstance.GetType()
.GetField(“<myProperty>kBackingField”,BindingFlags.Instance|BindingFlags.NonPublic);
intnewValue=1;
//setthevalueofmyInstance.myPropertybackingfieldtonewValue
fieldInfo.SetValue(myInstance,newValue);
Section63.8:CreateaninstanceofaGenericTypeandinvoke it’s method
varbaseType=typeof(List<>);
vargenericType=baseType.MakeGenericType(typeof(String)); varinstance=Activator.CreateInstance(genericType);
varmethod=genericType.GetMethod(“GetHashCode”);
varresult=method.Invoke(instance,newobject[]{});
Findpropertieswithacustomattribute-MyAttribute
varprops=t.GetProperties(BindingFlags.NonPublic|BindingFlags.Public| BindingFlags.Instance).Where(
prop=>Attribute.IsDefined(prop,typeof(MyAttribute)));
Findallcustomattributesonagivenproperty
varattributes=typeof(t).GetProperty(“Name”).GetCustomAttributes(false);
Enumerateallclasseswithcustomattribute-MyAttribute
staticIEnumerable<Type>GetTypesWithAttribute(Assemblyassembly){ foreach(Typetypeinassembly.GetTypes()){
if(type.GetCustomAttributes(typeof(MyAttribute),true).Length>0){
yieldreturntype;
}
}
}
Readvalueofacustomattributeatruntime
publicstaticclassAttributeExtensions
{
///<summary>
///Returnsthevalueofamemberattributeforanymemberinaclass.
/// (amemberisaField,Property,Method,etc…)
///<remarks>
///Ifthereismorethanonememberofthesamenameintheclass,itwillreturnthefirst one(thisappliestooverloadedmethods)
///</remarks>
///<example>
///ReadSystem.ComponentModelDescriptionAttributefrommethod’MyMethodName’inclass ‘MyClass’:
/// varAttribute=typeof(MyClass).GetAttribute(“MyMethodName”,(DescriptionAttributed)
=>d.Description);
///</example>
///<paramname=”type”>Theclassthatcontainsthememberasatype</param>
///<paramname=”MemberName”>Nameofthememberintheclass</param>
///<paramname=”valueSelector”>Attributetypeandpropertytoget (willreturnfirst instanceiftherearemultipleattributesofthesametype)</param>
///<paramname=”inherit”>truetosearchthismember’sinheritancechaintofindthe attributes;otherwise,false.Thisparameterisignoredforpropertiesandevents</param>
///</summary>
publicstaticTValueGetAttribute<TAttribute,TValue>(thisTypetype,stringMemberName, Func<TAttribute,TValue>valueSelector,boolinherit=false)whereTAttribute:Attribute
{
varatt= type.GetMember(MemberName).FirstOrDefault().GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault()asTAttribute;
if(att!=null)
{
returnvalueSelector(att);
returndefault(TValue);
}
}
Usage
//ReadSystem.ComponentModelDescriptionAttributefrommethod’MyMethodName’inclass’MyClass’varAttribute=typeof(MyClass).GetAttribute(“MyMethodName”,(DescriptionAttributed)=>d.Description);
Section 63.10: Instantiating classes that implement aninterface(e.g.pluginactivation)
Ifyouwantyourapplicationtosupportaplug-insystem,forexampletoloadplug-insfromassemblieslocatedin
pluginsfolder:
interfaceIPlugin
{
stringPluginDescription{get;}
voidDoWork();
}
Thisclasswouldbelocatedinaseparatedll
classHelloPlugin:IPlugin
{
publicstringPluginDescription=>”ApluginthatsaysHello”;publicvoidDo
Work()
{
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.
publicIEnumerable<IPlugin>InstantiatePlugins(stringdirectory)
{
varpluginAssemblyNames=Directory.GetFiles(directory,”*.addin.dll”).Select(name=>new FileInfo(name).FullName).ToArray();
//loadtheassembliesintothecurrentAppDomain,sowecaninstantiatethetypeslater
foreach(varfileNameinpluginAssemblyNames) AppDomain.CurrentDomain.Load(File.ReadAllBytes(fileName));
varassemblies=pluginAssemblyNames.Select(System.Reflection.Assembly.LoadFile); vartypesInAssembly=assemblies.SelectMany(asm=>asm.GetTypes());
varpluginTypes=typesInAssembly.Where(type=>typeof(IPlugin).IsAssignableFrom(type)); returnpluginTypes.Select(Activator.CreateInstance).Cast<IPlugin>();
}
Section63.11:GetaTypebynamewithnamespace
Todothisyouneedareferencetotheassemblywhichcontainsthetype.Ifyouhaveanothertypeavailablewhich you know is in the same assembly as the one you want you can do this:
typeof(KnownType).Assembly.GetType(typeName);
wheretypeNameisthenameofthetypeyouarelookingfor(includingthenamespace),andKnownTypeisthe type you know is in the same assembly.
Lessefficientbutmoregeneralisasfollows:
Typet=null;
foreach(AssemblyassinAppDomain.CurrentDomain.GetAssemblies())
{
if(ass.FullName.StartsWith(“System.”))
continue;
t=ass.GetType(typeName);
if(t!=null)
break;
}
NoticethechecktoexcludescanningSystemnamespaceassembliestospeedupthesearch.Ifyourtypemay actually be a CLR type, you will have to delete these two lines.
Ifyouhappen tohavethe fullyassembly-qualifiedtype nameincludingthe assemblyyoucan simplygetit 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’ssaysomeonecreatedaninstanceofList<T>likethatandpassesittoamethod:
varmyList=newList<int>(); ShowGenericArguments(myList);
whereShowGenericArgumentshasthissignature:
publicvoidShowGenericArguments(objecto)
soatcompiletimeyoudon’thaveanyideawhatgenericargumentshavebeenusedtocreateo.Reflectionprovides alotofmethodstoinspectgenerictypes.Atfirst,wecandetermineifthetypeofoisagenerictypeatall:
publicvoidShowGenericArguments(objecto)
{
if(o==null)return;
Typet=o.GetType();
if(!t.IsGenericType)return;
…
Type.IsGenericTypereturnstrueifthetypeisagenerictypeandfalseifnot.
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 constructedgenerictypes.AconstructedgenerictypeisforexampleaList<int>thathasaspecifictype argument for all its generic parameters.
The Typeclass provides two more properties,IsConstructedGenericTypeand IsGenericTypeDefinition, to distinguishtheseconstructedgenerictypesfromgenerictypedefinitions:
typeof(List<>).IsGenericType//true
typeof(List<>).IsGenericTypeDefinition//true
typeof(List<>).IsConstructedGenericType//false
typeof(List<int>).IsGenericType//true
typeof(List<int>).IsGenericTypeDefinition // false
typeof(List<int>).IsConstructedGenericType//true
Toenumeratethegenericargumentsofaninstance,wecanusetheGetGenericArguments()methodthatreturns an Typearray containing the generic type arguments:
publicvoidShowGenericArguments(objecto)
{
if(o==null)return; Type
t=o.GetType();
if(!t.IsConstructedGenericType)return;
foreach(TypegenericTypeArgumentint.GetGenericArguments()) Console.WriteLine(genericTypeArgument.Name);
}
Sothecallfromabove(ShowGenericArguments(myList))resultsinthisoutput:
Int32
Section63.13:Loopingthroughallthepropertiesofaclass
Typetype=obj.GetType();
//Torestrictreturnproperties.Ifallpropertiesarerequireddon’tprovideflag.
BindingFlagsflags=BindingFlags.Public|BindingFlags.Instance; PropertyInfo[]properties=type.GetProperties(flags);
foreach(PropertyInfopropertyinproperties)
{
Console.WriteLine(“Name:”+property.Name+”,Value:”+property.GetValue(obj,null));
}
About us and this blog
We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.
Request a free quote
We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.
Subscribe to our newsletter!
More from our blog
See all postsRecent Posts
- Chapter98:Networking 28/04/2024
- Chapter97:FileandStreamI/O 27/04/2024
- Chapter96:Delegates 26/04/2024