MCSD Web Applications: Code Reflection and Information; Working with Garbage Collection
Index
- Intro
- How to get type data
- Reflection
- Garbage collector
- Disposable objects
- Dispose vs Close vs Stop
- References
Intro
Welcome to this new posts related with MCSD certification. Today I bring a little bit of retrieving type data, some reflection, the garbage collector and the dispose interface. Let's get started!All the following information has been retrieved from the Microsoft Virtual Academy learning course: Programming in C# Jump Start. (see references at the end).
How to get type data
We can get type data in compile time or dynamically at runtime. At compile time you ask the definition of a particular class and at runtime you can interrogate an instance of a particular object and both ways will get a particular type. The type class represents the metadata within the class.var dog = new Dog { NumberOfLegs = 4 }; // At compile time Type t1 = typeof(Dog); // At runtime Type t2 = dog.GetType(); // output: Dog Console.WriteLine(t2.Name); // output: After002, Version=1.0.0.0, Culture= neutral, PublicKeyToken=null Console.WriteLine(t2.Assembly);
Typically, when you get a type you will be calling methods and so, which means you will need to get the whole instance of that type. There are a couple of ways to achieve this: using Activator.CreateInstance (under the reflection namespace) and Calling Invoke on a ConstructorInfo object. Please, see the example below.
var newDog = (Dog)Activator.CreateInstance(typeof(Dog)); var genericDog = Activator.CreateInstance(); // uses default constructor // with no defined parameters var dogConstructor = typeof(Dog).GetConstructors()[0]; var advancedDog = (Dog)dogConstructor.Invoke(null);
Besides methods you can be calling property and retrieving its content. See in this example how I get the type of the class "Animal" and then I create an instance of the property "Animal". In order to get the value I need to call the GetValue method from the property using the instance of our animal.
class Program { public void Property() { var horse = new Animal() { Name = "Ed" }; var type = horse.GetType(); var property = type.GetProperty("Name"); var value = property.GetValue(horse, null); // value == "Ed" } } public class Animal { public string Name { get; set; } }
Same thing if we'd like to work with methods. It's very similar to our previous example with properties.
class Program { public void Method() { var horse = new Animal(); var type = horse.GetType(); var method = type.GetMethod("Speak"); var value = (string)method.Invoke(horse, null); // value == "Hello" } } public class Animal { public string Speak() { return "Hello"; } }
Reflection
* Edited 27/04/15:Before starting with reflection I would like to tell you which the pros and cons of this technology are. As the main disadvantage we have the performance. Reflection isn't great at speed but on the other hand, there are a few things worth to look at:
- Determining dependencies of an assembly
- Location types which conform to an interface, derive from a base or abstract class and searching for members by attributes.
- In case you get a class which is not testable (not easy to work a mock class) you could use Reflection to inject some fake values within the class. *This is not standard but handy
- Debugging: dumping out a list of the loaded assemblies, their references, current methods and so.
Reflection inspects type metadata at runtime. The metadata contains info like: the type name, the containing assembly, constructors, methods, properties and so. Unfortunately it's expensive and takes time getting all this information. On the other side the power you get is simply great.
In the following example I'll be working with the class Dog. This class contains a couple of constructors which populate the property NumberOfLegs.
In the Main method I'll show you how to set that property up and how to interact with the constructors using reflection.
public class Dog { public int NumberOfLegs { get; set; } public Dog() { NumberOfLegs = 4; } public Dog(int legs) { NumberOfLegs = legs; } } class Program { public static void Main() { // with reflection var dog = Activator.CreateInstance(typeof(Dog)) as Dog; PropertyInfo[] properties = dog.GetType().GetProperties(); // alternative typeof(Dog).GetProperties(); PropertyInfo numberOfLegsproperty1 = properties[0]; // or PropertyInfo numberOfLegsProperty2 = null; foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.Name.Equals("NumberOfLegs", StringComparison.InvariantCulture)) { numberOfLegsProperty2 = propertyInfo; } } numberOfLegsproperty1.SetValue(dog, 3, null); Console.WriteLine(numberOfLegsProperty2.GetValue(dog, null)); // output 3 // use reflection to invoke different constructors var defaultconstructor = typeof (Dog).GetConstructor(new Type[0]); var legConstructor = typeof(Dog).GetConstructor(new[] { typeof(int) }); var defaultDog = (Dog)defaultconstructor.Invoke(null); Console.WriteLine(defaultDog.NumberOfLegs); // output 4 var legDog = (Dog)legConstructor.Invoke(new object[] { 5 }); Console.WriteLine(legDog.NumberOfLegs); // output 5 } }
Because I'm using strongly typed definitions by casting with "(Dog)" I can get all the properties and methods within those types using Visual Studio intellisense. In line 42, I'm taking one particular constructor passing the definition between brackets (.. {typeof (int) }). At the very bottom of the example we are invoking the compiler within the Dog class passing the parameter 5 to get a Dog object instance with five legs. Weird right?
It also worth to know you can interact with generics using Reflection.
Garbage collector
The garbage collector is an automatic memory management and it worries about objects are not in use any more. Those objects which are not in use and are taking memory and resources from our computer, those are the ones the GC removes from memory and deletes any reference in memory.For a periodic activity it may make sense to force the collector to run. Our application will wait until the GC finishes so take care when you run manually this action because it's a very expensive one.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Disposable objects
Some objects need explicit code to release resources that's when the IDisposable interface is useful. It marks that these types implement the Dispose method. The simple dispose pattern works well for simple scenarios and sealed types. See here below an example:public class AdvancedDemo : IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if(disposing) { // release managed resources } // release unmanaged resources } ~AdvancedDemo() { Dispose(false); } }
In the following scenario I'm opening a file (resource) using the method Open in the File class. This method returns a stream and I shouldn't forget to close that resource when I've finished working with that resource. I could use the Close method as the File.Open but there a better way. Microsoft provides the using statement (not the using at the top of a class) to wrap a particular behaviour in a method. This using will call the dispose method for you when it gets to the last line within brackets. See the following example:
public void x() { var path = "c:\test.txt"; using (var file = File.Open(path, FileMode.Open)) { //TODO } }