げんさん日記

プログラミングで気付いた事等を書きます。

ジェネリックを使用したモデルの保存・リストアを行います。

2019年11月06日 11時06分00秒 | C#
データモデル内にジェネリックが存在する場合に通常のSerialize及びDeserializeではエラーになり正しく処理できない為、データを一度メモリに出力し、その内容をシリアライズする事でジェネリックデータの保存を可能にします。その方法を下記に記します。

オブジェクトを保存する。
public void Save<T>(T saveObject, string fileName)
{
  // データをシリアライズして保存します。
  using (var memoryStream = new MemoryStream())
  {
    var binaryFormatter = new BinaryFormatter();
    binaryFormatter.Serialize(memoryStream, saveObject);
    System.IO.File.WriteAllBytes(fileName, memoryStream.ToArray());
    binaryFormatter = null;
  }
}

オブジェクトをリストアする。
public T Restore(string fileName)
{
  var binaryFormatter = new BinaryFormatter();

  try
  {
    using (var memoryStream = new MemoryStream(System.IO.File.ReadAllBytes(fileName)))
    {
      memoryStream.Seek(0, SeekOrigin.Begin);
      var obj = binaryFormatter.Deserialize(memoryStream);
      return (T)obj;
    }

  }
  finally
  {
    binaryFormatter = null;
  }
}


キャンバス上の位置を取得・設定を行います。

2019年11月06日 10時41分41秒 | WPF
キャンバス上に配置されているオブジェクトの位置を取得したり設定したりする方法を下記に記します。

キャンバス上の位置を取得します。
// キャンパス上のTOP・Leftを取得します。
var top = System.Windows.Controls.Canvas.GetTop(element);
var left = System.Windows.Controls.Canvas.GetLeft(element);

// 取得した内容をポイントに変換して返します。
return new Point(left, top);

キャンバス上の左位置を変更します。
System.Windows.Controls.Canvas.SetLeft(element, positionX);

キャンバス上の上位置を変更します。
System.Windows.Controls.Canvas.SetTop(element, positionY);

配列の要素を全て削除する。(メモリリーク対策)

2019年11月06日 10時13分18秒 | C#
配列要素を削除する場合にremoveとかclearを使用すると配列からは削除されるがメモリ上からは削除されない場合があります。その場合にメモリリークすることがあります。その対策としてDispose属性が存在する場合にはDisposeメソッドを実行し確実にメモリからの解放を行うものとする。その方法を下記に記します。

配列要素を全て削除する拡張クラスを作成します。
public static void RemoveAll<T>(this ICollection<T> values)
{
  // nullの時、処理を終了する。
  if (values == null)
  {
    return;
  }

  // 要素の数分繰り返します。
  foreach (var value in values)
  {
    // IDisposable型の時、Disposeを行います。
    IDisposable disp = value as IDisposable;
    if (disp != null)
    {
      disp.Dispose();
      disp = null;
    }
  }

  // 要素をクリアします。
  values.Clear();
}

使用例
public void OnClick()
{
  this.List.RemoveAll();
}
上記で配列情報がクリアされます。

Enumの内容をコンボボックス用のデータとして取得する。

2019年11月06日 09時49分12秒 | C#
enumに設定してある内容をコンボボックスのデータとして取得する方法を下記に記します。

enumの定義を下記のようにします。Descriptionに表示する内容を定義します。
public enum EncodeType
{
  [Description("shift_jis")]
  ShiftJis = 0,
  [Description("utf-8")]
  UTF8 = 1,
}

Enum値を取得する拡張クラスを作成します。
public static int Value(this Enum value)
{
  // Fieldを取得します。
  var fi = value.GetType().GetField(value.ToString());

  // Fieldから値を取得し返します。
  return (int)fi.GetValue(null);
}

Enum値に対応する名称を取得する拡張クラスを作成します。
public static string Name(this Enum value)
{
  // 指定されたEumのFieldを取得します。
  var fi = value.GetType().GetField(value.ToString());
  if (fi == null)
  {
    // 取得できなかった時、NULLを返します。
    return null;
  }

  // DescriptionAttributeを取得します。
  var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
  if (attributes != null && attributes.Length > 0)
  {
    // DescriptionAttributeが存在する時、DescriptionAttributeの内容を返します。
    return attributes[0].Description;
  }
  else
  {
    // DescriptionAttributeが存在しない時、値に対応する名称を返します。
    return value.ToString();
  }
}

コンボボックス用データを取得する拡張クラスを作成します。
public static ICollection GetComboData<T>(this T value)
{
  // Enumの値リストを取得します。
  var fields = value.GetType().GetFields();
  var enmName = value.GetType().Name;

  // 値リストからコンボデータを作成します。
  var datas = fields.ToList().Where(w => w.FieldType.Name == enmName).Select(s => new Models.ComboBoxModel()
   {
     Value = ((int)s.GetValue(null)).ToString(),
     Name = Name((Enum)s.GetValue(null)),
   }).ToList();

  // 作成したコンボデータを返します。
  return datas;
}
※Models.ComboBoxModelはValue とName を持つモデルです。

使用例
public void OnClick()
{
  var comboData = (default(EncodeType)).GetComboData();
}
上記でEnumの値を全て取得できますし、enumの内容が変更されても対応がenumの変更のみで終わる為、保守性が上がります。