2011年2月6日日曜日

C#でXmlシリアライズ/デシリアライズするヘルパー


C#でpublicなプロパティやフィールドをXMLにダンプするモジュールを作りまりた。
コードが横に長くてすみません。めんどくさいのでそのままにします。

 
public static class XmlSerializeHelper
{
private static readonly System.Text.Encoding _encoding = System.Text.Encoding.UTF8;

private static readonly XmlWriterSettings _xmlSettings = new XmlWriterSettings
{
Encoding = _encoding,
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.None,
};

public static XmlWriterSettings XmlSetting
{
get { return _xmlSettings; }
}

public static void Save<T>( string path, T o )
{
using ( StreamWriter sw = new StreamWriter( path, false, _encoding ) )
{
Save<T>( sw, o );
}
}

public static void Save<T>( StreamWriter sw, T o )
{
using ( XmlWriter writer = XmlWriter.Create( sw, _xmlSettings ) )
{
XmlSerializer xmlSerializer = new XmlSerializer( typeof( T ) );
xmlSerializer.Serialize( writer, o );
}
}

public static T Load<T>( string path )
{
using ( StreamReader sr = new StreamReader( path, _encoding ) )
{
return Load<T>( sr );
}
}

public static T Load<T>( StreamReader sr )
{
using ( XmlReader reader = XmlReader.Create( sr ) )
{
XmlSerializer xmlSerializer = new XmlSerializer( typeof( T ) );
return ( T ) xmlSerializer.Deserialize( reader );
}
}

}


使い方はこんな具合。
 
class SampleData
{
public string Name { get; set; }
public int Value { get; set; }
}

class Program
{
static void Main( string[] args )
{
List<SampleData> samples = new List<SampleData>{
new SampleData
{
Name = "Test1",
Value = 255
},
new SampleData
{
Name = "Test2",
Value = 100
}
};

/// XMLファイルに書出し
XmlSerializeHelper.Save<List<SampleData>>( "test.xml", samples );

/// XMLファイルから読込み
List<SampleData> loadedSamples = XmlSerializeHelper.Load<List<SampleData>>( "test.xml" );

foreach ( SampleData data in loadedSamples )
{
Console.WriteLine( string.Format( "{0} {1}", data.Name, data.Value ) );
}

}
}

なおDictionaryをダンプするには、ISerializerインターフェイスを実装する独自クラスが必要。
こちらのサイトが参考になります。

C#用のスニペット


VisualStudio用のスニペットを作ってみた。
まず下記のXMLを適当なフォルダに適当なファイル名(拡張子は.snippet)で保存する。
次にツール(T)>コードスニペットマネージャ(T)...からフォルダを指定して追加。
あとは、下記の一覧のショートカット(アンダースコア含む)をエディタ上で入力して、Tabキーを押せば補完できる。

ショートカット説明
_propプロパティ自動生成
_fieldフィールド自動生成
_classクラス自動生成


以下、フィルに保存するXML。ちょっと読めば雰囲気でカスタマイズ可能な内容。

プロパティ自動生成(_prop)



<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>prop</Title>
<Shortcut>_prop</Shortcut>
<Description>プロパティ用のスニペット</Description>
<Author></Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>viewname</ID>
<ToolTip>日本語名</ToolTip>
<Default>名前</Default>
</Literal>
<Literal>
<ID>type</ID>
<ToolTip>型</ToolTip>
<Default>string</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>プロパティ名</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>フィールド名</ToolTip>
<Default>_field</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[
/// <summery>$viewname$を設定/取得します。</summery>
public $type$ $property$
{
get{ return this.$field$; }
set{ this.$field$ = value; }
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>


フィールド自動生成(_field)



<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>field</Title>
<Shortcut>_field</Shortcut>
<Description>フィールド用のスニペット</Description>
<Author></Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>viewname</ID>
<ToolTip>日本語名</ToolTip>
<Default>名前</Default>
</Literal>
<Literal>
<ID>type</ID>
<ToolTip>型</ToolTip>
<Default>string</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>フィールド名</ToolTip>
<Default>_field</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[
/// <summery>$viewname$</summery>
private $type$ $field$;
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>


クラス自動生成(_class)



<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>class</Title>
<Shortcut>_class</Shortcut>
<Description>クラス用のスニペット</Description>
<Author></Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>description</ID>
<ToolTip>クラスの説明</ToolTip>
<Default></Default>
</Literal>
<Literal>
<ID>name</ID>
<ToolTip>クラス名</ToolTip>
<Default>MyClass</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[

/// <summery>
/// $description$
/// </summery>
class $name$
{
#region フィールド

#endregion

#region 初期化
/// <summery>
/// コンストラクタです。
/// </summery>
public $name$()
{}
#endregion

#region プロパティ

#endregion

#region メソッド

#endregion

}
]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>



もちろん標準のスニペットもあるが、細かいところが合わなかったりするので、結局は自分で作ったほうがしっくりくる。

C#の#regionのインデントを削除するマクロ


VisualStudioを使ってC#をコーディングしている際に、#regionを書くとコードのインデントと揃ってしまって不快なので、力技で置換するマクロを作ってみた。


Option Strict On
Option Explicit On

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.Diagnostics

Public Module FindAndReplace
Sub RemoveeRegionIndent()
DTE.Windows.Item("{CF2DDC32-8CAD-11D2-9302-005345000000}").Activate()
DTE.Find.Target = vsFindTarget.vsFindTargetCurrentProject
DTE.Find.FindWhat = "^.+{(\#region|\#endregion).*}$"
DTE.Find.ReplaceWith = "\1"
DTE.Find.MatchCase = False
DTE.Find.MatchWholeWord = False
DTE.Find.MatchInHiddenText = False
DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxRegExpr
DTE.Find.KeepModifiedDocumentsOpen = False
DTE.Find.FilesOfType = ""
DTE.Find.ResultsLocation = vsFindResultsLocation.vsFindResultsNone
DTE.Find.Action = vsFindAction.vsFindActionReplaceAll
If (DTE.Find.Execute() = vsFindResult.vsFindResultNotFound) Then
'Throw New System.Exception("vsFindResultNotFound")
End If
DTE.Windows.Item("{CF2DDC32-8CAD-11D2-9302-005345000000}").Close()
End Sub
End Module