Vanmorgen wakker geworden met een schuurpapieren keel, lichte hoofdpijn en moe, met een paracetamol flink wat uurtjes geslapen. Rustig aan gedaan vandaag, dus ben nu weer redelijk fit. Kan ik mooi door met module 4, code reflection and information; werken met Garbage Collection. Dat klinkt wederom als niet onbekend materiaal. Het gaat dus om het 4e deel van de C# Jump Start Video.
We beginnen met reflection. Het inspecteert metadata van types tijdens runtime. Je kunt hiermee het type opvragen, de assembly waar het type onderdeel van uit maakt, constructors, eigenschappen, methoden en attributen. Hierdoor kun je methoden dynamisch op runtime uitvoeren. Iemand levert je bijvoorbeeld een slecht gedocumenteerde DLL aan. Dynamische extensies die je tijdens runtime inlaadt. Je kunt type data opvragen statisch tijdens compile type. typeof(Dog); Je kunt het ook dynamisch tijdens runtime doen, Type t2 = dog.GetType();
Dynamisch een type instantiëren kan met Activator.CreateInstance: var newDog = (Dog)Activator.CreateInstance(typeof(Dog));
Of met een Invoke op een ConstructorInfo object (geavanceerd scenario): var genericDoc = Activator.CreateInstance(Dog){};
Ook nog een standaard constructor met geen gedefinieerde parameters:
var dogConstructor = typeof (Dog).GetConstructors()[0];
string[] arr;
var advancedDog = (Dog)dogConstructor.Invoke(arr);
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"
}void Method()
{
var horse = new Animal();
var type = horse.GetType();
var method = type.GetMethod("Speak");
var value = (string)method.Invoke(horse, null);
// value = "Hello"
}
We gaan naar het demo-project, 004. var dog = Activator.CreateInstance(typeof (Dog)) as Dog;
Door de "as" snapt de var dog dat de eigenschap numberoflegs beschikbaar is.
Met PropertyInfo[] properties = dog.GetType().GetProperties() kun je de eigenschappen opvragen.
We gaan door alle properties heen. PropertyInfo numberOfLegs = propertyInfo;
numberOfLegs.SetValue(dog, 3, null);
var defaultConstructor = typeof(Dog).GetConstructor(new Type[0]);
var legConstructor = typeof(Dog).GetConstructor(new [] {typeof (int)});
var legDog = (Dog) legConstructor.Invoke(new object[]{5});
Dit zijn kleine overzichten hoe je dit kunt gebruiken, in een echt scenario zul je deze zaken op een externe DLL uitvoeren.
We gaan door met "Garbage Collection". In .Net heb je de runtime waarbij de niet gebruikte geheugenruimte weer vrijgegeven wordt. Het automatische memory-management. Objecten die geen referentie meer hebben (wezen/orphans) worden niet meteen opgeruimd, maar periodiek. Er zijn veel factoren die de frequentie van GB beïnvloeden. De "wezen" worden ook niet allemaal gelijktijdig opgeruimd. En uiteindelijk is GB een "dure" actie. Kleine objecten worden daarom eerst opgeruimd. Lokale variabelen in een method worden zodra de method uitgevoerd is opgeruimd. In de meeste gevallen moet je de Garbage Collector zelf zijn werk laten doen. Als je het zelf doet, dan alleen in specifieke situaties.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Als je een "goede burger" wilt zijn, moet je zorgen dat jouw class een IDisposable implementeert.
Het werkt goed voor simpele scenario's en sealed types. public class Demo : IDisposable.
In je eigen class kun je dan een public void Dispose() toevoegen, waarin je bijvoorbeeld een variabele array met 10.000 waardes op "null" kunt zetten om het vrij te geven.
Het geavanceerde Dispose Pattern.
Dit gebruiken we voor niet triviale disposable objecten. In het voorbeeld zien we:
public class AdvancedDemo : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// release managed resourced
}
// release unmanaged resources
}
~AdvancedDemo()
{
Dispose(false);
}
}
Met een using-statement kun je zorgen dat een IDisposable netjes opgeruimd wordt. Vaak genoeg gebruikt. Hier wordt het gebruikt om een bestand te openen. Voordeel hiervan is dat je geen Close hoeft uit te voeren, omdat met using het bestand al vrijgegeven wordt.
We krijgen een vergelijking tussen Dispose / Close / Stop
Close, kan functioneel gelijk zijn als dispose. Kan eeen subset van de dispose functionaliteit zijn.
Een object wat "geclosed" is, kun je heropenen: IDbConnection.
Stop is vergelijkbaar met Close. Het kan herstart worden, denk aan een Timer.
De consequenties kunnen heftig zijn. Gelockte bestanden. Memory leaks. Objecten die buiten de scope vallen kunnen gerefereerd worden door objecten die in scope zijn en daardoor blijven leven. Events kunnen een bron van memory-leaks zijn. Events kunnen referenties naar objecten vasthouden. Oplossing? Pro-actief afmelden voor de events. Met weak references kun je sommige memory leak events voorkomen.
Een weak reference zorgt voor een reference die de Garbage Collector negeert. Dit voer je uit door een lokale variabele te refereren aan de weak reference value. Dit zorgt dat ervoor dat deze beschikbaar blijft tot de lokale variabele uit scope is.