Created
March 4, 2017 17:48
-
-
Save lbargaoanu/32a7586583a6864ae9308161b1c998db to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Xml; | |
using System.Reflection; | |
using System.Diagnostics; | |
using System.Globalization; | |
using System.ComponentModel; | |
using System.Collections.Generic; | |
public static class ConfigurationManager | |
{ | |
private static readonly Dictionary<Type, Defaults> defaults = new Dictionary<Type, Defaults>(); | |
private const string FileName = "Domain.config"; | |
static ConfigurationManager() | |
{ | |
XmlDocument document = new XmlDocument(); | |
document.Load(FileName); | |
foreach(XmlElement typeElement in document.SelectNodes("types/type")) | |
{ | |
string typeName = typeElement.Attributes["name"].Value; | |
string assemblyName = typeElement.Attributes["assembly"].Value; | |
Type type = Type.GetType(typeName + "," + assemblyName, true); | |
defaults.Add(type, new Defaults(type, typeElement)); | |
} | |
} | |
public static void Initialize(object obj) | |
{ | |
if(obj == null) | |
{ | |
throw new ArgumentNullException("obj"); | |
} | |
Defaults def; | |
if(defaults.TryGetValue(obj.GetType(), out def)) | |
{ | |
def.Set(obj); | |
} | |
} | |
struct Default | |
{ | |
readonly FieldInfo fieldInfo; | |
readonly object value; | |
public Default(FieldInfo fieldInfo, string strValue) | |
{ | |
TypeConverter converter = TypeDescriptor.GetConverter(fieldInfo.FieldType); | |
if(converter.GetType() == typeof(TypeConverter)) | |
{ | |
throw new ApplicationException("Cannot find converter for type " + fieldInfo.FieldType.AssemblyQualifiedName); | |
} | |
try | |
{ | |
value = converter.ConvertFromString(null, CultureInfo.InvariantCulture, strValue); | |
} | |
catch(Exception ex) | |
{ | |
throw new ApplicationException("Cannot initialize field \"" + fieldInfo.Name + "\" of type " + fieldInfo.ReflectedType.AssemblyQualifiedName, ex); | |
} | |
this.fieldInfo = fieldInfo; | |
} | |
public void Set(object obj) | |
{ | |
fieldInfo.SetValue(obj, value); | |
} | |
public void Set(TypedReference obj) | |
{ | |
fieldInfo.SetValueDirect(obj, value); | |
} | |
} | |
struct Defaults | |
{ | |
// the chain of parents that got us here | |
readonly FieldInfo[] parentFields; | |
// the primitive fields of our type, ThisField.FieldType | |
readonly Default[] defaults; | |
// the non-primitive fields of our type, ThisField.FieldType | |
readonly Defaults[] nestedDefaults; | |
public Defaults(Type type, XmlElement typeElement, FieldInfo[] parentFields) | |
{ | |
this.parentFields = parentFields; | |
List<Default> defaultsList = new List<Default>(typeElement.ChildNodes.Count); | |
List<Defaults> nestedDefaultsList = new List<Defaults>(); | |
foreach(XmlElement fieldElement in typeElement.SelectNodes("field")) | |
{ | |
string name = fieldElement.Attributes["name"].Value; | |
FieldInfo fieldInfo = type.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); | |
if(fieldInfo == null) | |
{ | |
throw new ApplicationException("Cannot find field " + name + " of type " + type.AssemblyQualifiedName); | |
} | |
if(fieldElement.HasChildNodes) | |
{ | |
nestedDefaultsList.Add(new Defaults(fieldInfo.FieldType, fieldElement, AddThisParent(parentFields, fieldInfo))); | |
} | |
else | |
{ | |
string strValue = fieldElement.Attributes["value"].Value; | |
defaultsList.Add(new Default(fieldInfo, strValue)); | |
} | |
} | |
defaults = defaultsList.ToArray(); | |
nestedDefaults = (nestedDefaultsList.Count > 0) ? nestedDefaultsList.ToArray() : null; | |
} | |
public Defaults(Type type, XmlElement typeElement) : this(type, typeElement, null) | |
{ | |
} | |
private static FieldInfo[] AddThisParent(FieldInfo[] parentFields, FieldInfo fieldInfo) | |
{ | |
FieldInfo[] newParentFields; | |
if(parentFields == null) | |
{ | |
newParentFields = new FieldInfo[] { fieldInfo }; | |
} | |
else | |
{ | |
newParentFields = new FieldInfo[parentFields.Length + 1]; | |
Array.Copy(parentFields, newParentFields, parentFields.Length); | |
newParentFields[newParentFields.Length - 1] = fieldInfo; | |
} | |
return newParentFields; | |
} | |
// this object handles this FieldInfo and its children | |
private FieldInfo ThisField | |
{ | |
get | |
{ | |
return parentFields[parentFields.Length - 1]; | |
} | |
} | |
public void Set(object obj) | |
{ | |
if(parentFields != null) | |
{ | |
// we must take extra care for structs; we cannot use SetField with an object parameter because we box and change that boxed instance | |
// instead we must work with TypedReference-s and pass the root object along recursively | |
if(ThisField.FieldType.IsValueType) | |
{ | |
TypedReference referenceToSet = TypedReference.MakeTypedReference(obj, parentFields); | |
foreach(Default def in defaults) | |
{ | |
def.Set(referenceToSet); | |
} | |
if(nestedDefaults != null) | |
{ | |
object parent = null; | |
foreach(Defaults def in nestedDefaults) | |
{ | |
if(def.ThisField.FieldType.IsValueType) | |
{ | |
// cannot update obj, the chaining is done through the parent fields | |
def.Set(obj); | |
} | |
else | |
{ | |
if(parent == null) | |
{ | |
// if we are a "nested" object we need to update the object to set; obj is actually our parent now; make it point to us | |
parent = ThisField.GetValue(obj); | |
} | |
def.Set(parent); | |
} | |
} | |
} | |
return; | |
} | |
// if we are a "nested" object we need to update the object to set; obj is actually our parent now; make it point to us | |
obj = ThisField.GetValue(obj); | |
} | |
if (obj == null) | |
{ | |
throw new ArgumentNullException("Field: " + ThisField.ToString()); | |
} | |
foreach (Default def in defaults) | |
{ | |
def.Set(obj); | |
} | |
if(nestedDefaults != null) | |
{ | |
foreach(Defaults def in nestedDefaults) | |
{ | |
def.Set(obj); | |
} | |
} | |
} | |
} | |
} | |
//namespace Program | |
//{ | |
// class Program | |
// { | |
// static void Main(string[] args) | |
// { | |
// TestThread th = new TestThread("dedw"); | |
// } | |
// } | |
// struct StrNested | |
// { | |
// int z; | |
// } | |
// class Base | |
// { | |
// string _string = null; | |
// } | |
// struct Str | |
// { | |
// public Str(int i) | |
// { | |
// zzz = new StrNested(); | |
// b = new Base(); | |
// x = y = 9; | |
// } | |
// StrNested zzz; | |
// int x; | |
// int y; | |
// Base b; | |
// } | |
// public class TestThread | |
// { | |
// Str structura = new Str(1); | |
// int _int = 0; | |
// internal float _float = 0; | |
// protected string _string = null; | |
// public DateTime _dateTime = DateTime.MinValue; | |
// TestThread _testThread = null; | |
// Base threadB = new Base(); | |
// public TestThread(string name) | |
// { | |
// ConfigurationManager.Initialize(this); | |
// } | |
// } | |
//} | |
// | |
//<?xml version="1.0" encoding="utf-8" ?> | |
//<types> | |
// <type name="Program.TestThread" assembly="Console2005"> | |
// <field name="threadB"> | |
// <field name="_string" value="class in class" /> | |
// </field> | |
// <field name="_int" value="-1" /> | |
// <field name="_float" value="23.45" /> | |
// <field name="_string" value="iaca o venit" /> | |
// <field name="_dateTime" value="3/31/2006 10:59:26 AM" /> | |
// <field name="structura"> | |
// <field name="x" value="65" /> | |
// <field name="y" value="89" /> | |
// <field name="zzz"> | |
// <field name="z" value="17" /> | |
// </field> | |
// <field name="b"> | |
// <field name="_string" value="class in struct" /> | |
// </field> | |
// </field> | |
// </type> | |
//</types> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment