インスタンス数を制限するクラスを定義する必要がよくある。実装方法のひとつに、コンストラクタを隠蔽して、静的メソッド内でインスタンス数チェックを行いインスタンスを返させる手法が考えられる。というわけで、こんな風に書いたとする。
class Kanjo { // インスタンス数 private static int instansNum = 0; // 三人官女は 3 人まで private static const int maxInstansNum = 3; // 静的なメソッドよりインスタンスを作成する public static Kanjo CreateInstance () { // インスタンス数チェック if (instansNum < maxInstansNum) { instansNum++; // インスタンス数を加算 return new Kanjo (); // 官女を作成して返す } // 例外の種類は適当 throw new OverflowException (); } private Kanjo () { // 官女の初期化を行う } }
上記のコードはコンパイルできない。「定数 'Kanjo.maxInstansNum' を static に指定することはできません。」というエラーになってしまう。static const なんて C++ だと普通のコードなので少々悩んだ。C# の場合は const をつけた時点で静的メンバになるので、static をつけることが出来ない。const をつけると static がなくとも静的なメソッドからアクセス可能になる。
// static がつかなくても、静的なメソッドからアクセスが可能 const int maxInstansNum = 3;
なんか気持ちわるー。
ちなみに、C# には readonly というキーワードもあるが、こちらはインスタンスが作られるので、下記の記述が可能。
// readonly の場合は static をつけないと静的なメンバにならない static readonly int maxInstansNum = 3;
いまさら気づきましたが…。C++ から来た人間としてはかなり不便に感じます。別案を考えなきゃな。
参考になるかもなぎろん。
フレンドクラスに対する代替案 - C#、VB.NET、ASP.NET、C /CLI、Java
.NET Frameworks 3.5 SP1 より、BindingBase に StringFormat プロパティが追加されて、話題になりました。が、こんなの書いてみてもちっともフォーマットされず、悩みました。
<Window x:Class="StringFormatTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
Title="Window1">
<Window.Resources>
<ObjectDataProvider x:Key="DayOfWeek" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="System:DayOfWeek"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource DayOfWeek}, StringFormat={}{0}!}"/>
</Window>
これは、ItemsControl クラスの ItemStringFormat プロパティの値のほうが優先されるためです。こちらは、意図したとおりに「!」が追加されて表示されます。
<ListBox ItemsSource="{Binding Source={StaticResource DayOfWeek}}" ItemStringFormat="{}{0}!"/>
その他、ContentControl を継承するコントロールの場合 ContentStringFormat プロパティが、HeaderedContentControl や HeaderedItemsControl の場合、HeaderStringFormat プロパティが存在して、Binding に設定した StringFormat より優先されるようです。
WPFの「コマンド」 - .NET Claimwork 3.0
コマンドの使い方がさっくりかかれててわかりやすいです。
XmlSerializer を使う (シリアル化編) で Person クラスの年齢の計算がてきとうだったので、この辺を参考にして拡張メソッドを作ってみました。
namespace DateTimeExtensions
{
public static class GetAgeExtension
{
public static int GetAge (this DateTime birthDay, DateTime today)
{
DateTime tempDate = new DateTime (birthDay.Year, 1, 1);
tempDate = tempDate.AddDays (today.DayOfYear - 1);
return today.Year - birthDay.Year + (birthDay <= tempDate ? 0 : -1);
}
}
}
これでこんな風に書けますね。
// ソースの先頭に以下を追加 // using DateTimeExtensions; // Person の配列を作る var people = Enumerable.Range (0, 5) .Select (index => new { index = index, day = new DateTime (1975 + index, index + 1, index + 1) }) .Select (param => new Person () { Name = string.Format ("{0:ddd}", param.day) + suffix [param.index % 2], Gender = (GenderEnum) (param.index % 2), Birthday = param.day, Age = param.day.GetAge (DateTime.Now) // こんな感じで! }).ToArray ();
System.Xml.Serialization 名前空間に XmlSerializer というクラスがある。その名のとおり、データを XML 形式でシリアル化してくれるというもの。
シリアル化するクラスは public でないといけないらしい。クラスメンバについても public なプロパティや変数が対象になる。メソッドは対象とならない。また、get/set の両方が可能である必要がある。
また、デフォルトコンストラクタのないクラスは扱えない。メンバにも含めることが出来ない。
// 性別 public enum GenderEnum : int { Male, Female, } // ありがちなクラス public class Person { public string Name { get; set; } public GenderEnum Gender { get; set; } public DateTime Birthday { get; set; } public int Age { get; set; } }
上記 Person クラスのシリアライズはこんな感じ。
using System;
using System.Linq;
class XmlSerializeSample
{
static void Main ()
{
// 名前生成用w
var suffix = new string [] { "郎", "子" };
// Person の配列を作る
var people = Enumerable.Range (0, 5)
.Select (index => new { index = index, day = new DateTime (1975 + index, index + 1, index + 1) })
.Select (param => new Person ()
{
Name = string.Format ("{0:ddd}", param.day) + suffix [param.index % 2],
Gender = (GenderEnum) (param.index % 2),
Birthday = param.day,
Age = DateTime.Now.Year - param.day.Year // 年齢が適当ですね…
}).ToArray ();
// XmlSerializer を使用したシリアライズ
var serializer = new System.Xml.Serialization.XmlSerializer (typeof (Person []));
var stream = new System.IO.StreamWriter("C:\\people.xml", false);
serializer.Serialize(stream, people);
stream.Close();
}
}
LocBAML を使用してローカライズする方法が説明されています。ただし、UICulture の記述を .csproj ファイルに追加する際は、閉じタグ部分に気をつける必要があります。
<UICulture>ja-JP</UICulture>