lipsync/Boare.Lib.AppUtil/XmlStaticMemberSerializer.cs

210 lines
9.1 KiB
C#
Raw Permalink Normal View History

/*
* 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 {
/// <summary>
/// クラスのstaticメンバーのxmlシリアライズ/デシリアライズを行うclass
/// </summary>
public class XmlStaticMemberSerializer {
/// <summary>
/// ターゲットとなるクラスから,シリアライズするメンバーを抽出する時に使用
/// </summary>
private class MemberEntry {
/// <summary>
/// プロパティ/フィールドの名前
/// </summary>
public string Name;
/// <summary>
/// プロパティ/フィールドの型
/// </summary>
public Type Type;
/// <summary>
/// プロパティ/フィールドのデフォルト値
/// </summary>
public object Default;
public MemberEntry( string name, Type type, object default_ ) {
Name = name;
Type = type;
Default = default_;
}
}
/// <summary>
/// シリアライズする対象の型staticメンバーだけなのでインスタンスではなく型を保持
/// </summary>
private Type m_item;
/// <summary>
/// シリアライズ/デシリアライズするための内部型
/// </summary>
private Type m_config_type = null;
/// <summary>
/// m_config_typeで初期化されたシリアライザ
/// </summary>
private XmlSerializer m_xs = null;
private XmlStaticMemberSerializer() {
}
/// <summary>
/// 指定された型をシリアライズするための初期化を行います
/// </summary>
/// <param name="item"></param>
public XmlStaticMemberSerializer( Type item ) {
m_item = item;
}
/// <summary>
/// シリアライズを行い,ストリームに書き込みます
/// </summary>
/// <param name="stream"></param>
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 );
}
/// <summary>
/// 指定したストリームを使って,デシリアライズを行います
/// </summary>
/// <param name="stream"></param>
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;
}
}
}
}
/// <summary>
/// シリアライズ用の内部型をコンパイルしm_xsが使用できるようにします
/// </summary>
private void GenerateConfigType() {
List<MemberEntry> 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 );
}
}
/// <summary>
/// 設定ファイルから読込むための型情報を蒐集
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
private static List<MemberEntry> CollectScriptConfigEntries( Type item ) {
List<MemberEntry> config_names = new List<MemberEntry>();
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;
}
/// <summary>
/// 指定した型から、Reflectionを使ってxmlシリアライズ用のクラスをコンパイルするためのC#コードを作成します
/// </summary>
/// <param name="implemented"></param>
/// <returns></returns>
private static string GenerateClassCodeForXmlSerialization( List<MemberEntry> 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;
}
}
}