/*
* XmlStaticMemberSerializer.cs
* Copyright (c) 2009 kbinani
*
* This file is part of Boare.Lib.AppUtil.
*
* Boare.Lib.AppUtil is free software; you can redistribute it and/or
* modify it under the terms of the BSD License.
*
* Boare.Lib.AppUtil is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;
using Microsoft.CSharp;
namespace Boare.Lib.AppUtil {
///
/// クラスのstaticメンバーのxmlシリアライズ/デシリアライズを行うclass
///
public class XmlStaticMemberSerializer {
///
/// ターゲットとなるクラスから,シリアライズするメンバーを抽出する時に使用
///
private class MemberEntry {
///
/// プロパティ/フィールドの名前
///
public string Name;
///
/// プロパティ/フィールドの型
///
public Type Type;
///
/// プロパティ/フィールドのデフォルト値
///
public object Default;
public MemberEntry( string name, Type type, object default_ ) {
Name = name;
Type = type;
Default = default_;
}
}
///
/// シリアライズする対象の型.staticメンバーだけなので,インスタンスではなく型を保持
///
private Type m_item;
///
/// シリアライズ/デシリアライズするための内部型
///
private Type m_config_type = null;
///
/// m_config_typeで初期化されたシリアライザ
///
private XmlSerializer m_xs = null;
private XmlStaticMemberSerializer() {
}
///
/// 指定された型をシリアライズするための初期化を行います
///
///
public XmlStaticMemberSerializer( Type item ) {
m_item = item;
}
///
/// シリアライズを行い,ストリームに書き込みます
///
///
public void Serialize( Stream stream ) {
if ( m_config_type == null ) {
GenerateConfigType();
}
ConstructorInfo ci = m_config_type.GetConstructor( new Type[]{} );
object config = ci.Invoke( new object[]{} );
foreach ( FieldInfo target in m_config_type.GetFields() ) {
foreach ( PropertyInfo pi in m_item.GetProperties( BindingFlags.Public | BindingFlags.Static ) ) {
if ( target.Name == pi.Name && target.FieldType.Equals( pi.PropertyType ) && pi.CanRead && pi.CanWrite ) {
target.SetValue( config, pi.GetValue( m_item, new object[] { } ) );
break;
}
}
foreach ( FieldInfo fi in m_item.GetFields( BindingFlags.Public | BindingFlags.Static ) ) {
if ( target.Name == fi.Name && target.FieldType.Equals( fi.FieldType ) ) {
target.SetValue( config, fi.GetValue( m_item ) );
break;
}
}
}
m_xs.Serialize( stream, config );
}
///
/// 指定したストリームを使って,デシリアライズを行います
///
///
public void Deserialize( Stream stream ) {
if ( m_config_type == null ) {
GenerateConfigType();
}
object config = m_xs.Deserialize( stream );
if ( config == null ) {
throw new ApplicationException( "failed serializing internal config object" );
}
foreach ( FieldInfo target in m_config_type.GetFields() ) {
foreach ( PropertyInfo pi in m_item.GetProperties( BindingFlags.Public | BindingFlags.Static ) ) {
if ( target.Name == pi.Name && target.FieldType.Equals( pi.PropertyType ) && pi.CanRead && pi.CanWrite ) {
pi.SetValue( m_item, target.GetValue( config ), new object[] { } );
break;
}
}
foreach ( FieldInfo fi in m_item.GetFields( BindingFlags.Public | BindingFlags.Static ) ) {
if ( target.Name == fi.Name && target.FieldType.Equals( fi.FieldType ) ) {
fi.SetValue( m_item, target.GetValue( config ) );
break;
}
}
}
}
///
/// シリアライズ用の内部型をコンパイルし,m_xsが使用できるようにします
///
private void GenerateConfigType() {
List config_names = CollectScriptConfigEntries( m_item );
string code = GenerateClassCodeForXmlSerialization( config_names, m_item );
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add( "System.Windows.Forms.dll" );
parameters.ReferencedAssemblies.Add( "System.dll" );
parameters.ReferencedAssemblies.Add( "System.Drawing.dll" );
parameters.ReferencedAssemblies.Add( "System.Xml.dll" );
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;
parameters.IncludeDebugInformation = true;
CompilerResults results = provider.CompileAssemblyFromSource( parameters, code );
Assembly asm = results.CompiledAssembly;
if ( asm.GetTypes().Length <= 0 ) {
m_config_type = null;
m_xs = null;
throw new ApplicationException( "failed generating internal xml serizlizer" );
} else {
m_config_type = (asm.GetTypes())[0];
m_xs = new XmlSerializer( m_config_type );
}
}
///
/// 設定ファイルから読込むための型情報を蒐集
///
///
///
private static List CollectScriptConfigEntries( Type item ) {
List config_names = new List();
foreach ( PropertyInfo pi in item.GetProperties( BindingFlags.Static | BindingFlags.Public ) ) {
object[] attrs = pi.GetCustomAttributes( true );
foreach ( object obj in attrs ) {
if ( obj.GetType().Equals( typeof( System.Xml.Serialization.XmlIgnoreAttribute ) ) ) {
continue;
}
}
if ( pi.CanRead && pi.CanWrite ) {
config_names.Add( new MemberEntry( pi.Name, pi.PropertyType, pi.GetValue( item, new object[] { } ) ) );
}
}
foreach ( FieldInfo fi in item.GetFields( BindingFlags.Static | BindingFlags.Public ) ) {
object[] attrs = fi.GetCustomAttributes( true );
foreach ( object obj in attrs ) {
if ( obj.GetType().Equals( typeof( System.Xml.Serialization.XmlIgnoreAttribute ) ) ) {
continue;
}
}
config_names.Add( new MemberEntry( fi.Name, fi.FieldType, fi.GetValue( item ) ) );
}
return config_names;
}
///
/// 指定した型から、Reflectionを使ってxmlシリアライズ用のクラスをコンパイルするためのC#コードを作成します
///
///
///
private static string GenerateClassCodeForXmlSerialization( List config_names, Type item ) {
// XmlSerialization用の型を作成
string code = "";
code += "using System;\n";
code += "namespace Boare.Lib.AppUtil{\n";
code += " public class StaticMembersOf" + item.Name + "{\n";
foreach ( MemberEntry entry in config_names ) {
code += " public " + entry.Type.ToString() + " " + entry.Name + ";\n";
}
code += " }\n";
code += "}\n";
return code;
}
}
}