- PR -

[C# 2.0] ジェネリクスについて

1
投稿者投稿内容
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2006-12-31 13:04
ジェネリクスに格納されている型に対してそれぞれ別の処理したい場合はどのようにすればよいのでしょうか? XmlSerializerもSoapSerializerもほしいものとは違うので自分で作っているのですが、List<T>を取得する処理に戸惑ってます。

コード:

// ベースとなる型の取得処理
string GetString(string xpath);
Bitmap GetBitmap(string xpath);
int GetInt(string xpath);
// ...

// List<T>の取得処理
List<T> GetList<T>(string xpath)
{
XmlNode parentNode = xmlDocument.SelectSingleNode(xpath);
List<T> list = new List<T>();

foreach(XmlNode node in parentNode.ChildNodes)
{
if(typeof(T) == typeof(string))
{
// string 専用処理
list.Add((T)GetString(node.BaseURI));
}
if(typeof(T) == typeof(Bitmap))
{
// Bitmap 専用処理
list.Add((T)GetBitmap(node.BaseURI));
}
// ....
}
return list;
}



みたいなことをしたいのですが string/Bitmap/etc... から Tには変換できないんで…

その他のコードについても試してないからほかの部分で動かないかもしれません、そういうものがあった場合それについても指摘していただけると喜ばしいです。

_________________
9uiet design( http://quietdesign.rental.allinoneserver.net/ ) - タブ型デスクトップガジェット開発中。Pluginの開発してくれると嬉しいかも。

[ メッセージ編集済み 編集者: 有末 清華 編集日時 2006-12-31 13:11 ]

[ メッセージ編集済み 編集者: 有末 清華 編集日時 2006-12-31 13:14 ]
Kazuki
ぬし
会議室デビュー日: 2004/10/13
投稿数: 298
投稿日時: 2006-12-31 14:34
今実際に動かせる環境が無いんで動く保証はないですが・・・
こんな風にしてみては??

コード:
// 型ごとの処理のためのインターフェイス
public interface IHandler<T>
{
  T GetObject(string xpath);
}



コード:
// GetListはxpathとIHandler<T>を受け取る
public class MySerializer
{
  List<T> GetList(string xpath, IHandler<T> handler)
  {
    XmlNode parentNode = xmlDocument.SelectSingleNode(xpath);    
    List<T> list = new List<T>();

    foreach(XmlNode node in parentNode.ChildNodes)
    {
      // 処理はhandlerに任せる
      list.add(handler.GetObject(node.BaseURI));
    }
    return list;
  }
}



使うときは、型ごとに処理を書いて
コード:
public class StringHandler : IHandler<string> 
{
  public string GetObject(string xpath)
  {
    // string
    return ....;
  }
}



こんな感じで呼び出す
コード:
List<string> list = new MySerializer().GetList("xpath", new StringHandler());



実際問題IHandlerのGetObjectメソッドにはNodeのインスタンス渡したりとか
色々考えないと処理できないでしょうが。。。
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-01-01 03:58
やはりそういう方法しかないですかね…うーん実際はこのデータではビットマップ等使わないんでXmlSerializerでいけるんですが、ジェネリクスで簡単に書けるならと思って聞いてみたんですが(苦笑。

まぁもちは餅屋で、ここはXmlSerializerでまかなえるんで彼に任せることにします。

ありがとうございました^^
_________________
有末 清華
crazy(){for;;{you();}} - プログラマの覚書
Kazuki
ぬし
会議室デビュー日: 2004/10/13
投稿数: 298
投稿日時: 2007-01-01 10:45
引用:

XmlSerializerもSoapSerializerもほしいものとは違うので自分で作っているのですが、List<T>を取得する処理に戸惑ってます。


引用:

ここはXmlSerializerでまかなえるんで


結局何が目的なのかわからないです。
目的がわかれば、もう少しいい方法があるかもしれません。
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-01-01 12:50
えっと、作ってるソフトで以下の種類のファイルが必要になったんです。


  • スキン用のファイル
  • ユーザープロファイル(ユーザー個々の設定)
  • 設定ファイル(アプリケーションの設定ファイル)
  • 作成したガジェット個々のファイル


ここで、作成したがジェット個々のファイルに関してはガジェットがプラグインなので最終的に保存されるデーター形式が不明なので BinaryFormatter を使ってバイナリでシリアライズすることにしました。(Soapだといくつか保存されない)

ほかのデーター形式に関しては簡単に編集可能にするためにXml形式で保存したかったので最初はXmlSerializerを使うことを検討しましたが、XmlSerializerだとISerializableが使えなかったのでシリアライズされたファイルのバージョン管理やビットマップ・フォント等のデータが保存できないので断念しました(スキン用のファイルでは下記のようにして画像やフォントを記載したかった)

コード:
<Skin>
    <BackgroundImage>
        <File>./Images/background.bmp</File>
    </BackgroundImage>
    <Font>
        <FontFamily>Tahoma</FontFamily>
        <Size>8</Size>
        <Style>Regular</Style>
    </Font>
</Skin>



そこでSoapを使うことを検討しましたがSoapで出力されるXmlファイルは複雑で読みにくいので断念しました。

それで最終的に自分でXmlのコードを読み込むクラスを作成しました、下記のようなものです。(書き込むクラスは別にWriterの形で存在)

コード:
//
// ConfigurationXmlReader Class
//
XmlDocument xmlDocument;
string GetString(string xpath)
{
     return xmlDocument.SelectSingleNode(xpath).InnerText;
}
int GetInt(string xpath);
double GetDouble(string xpath);
bool GetBoolean(string xpath);
// ...
Size GetSize(string xpath)
{
     int w = GetInt(xpath + "/Width");
     int h = GetInt(xpath + "/Height");
     return new Size(w,h);
}
// ...
Bitmap GetBitmap(string xpath)
{
     string filename = GetString(xpath + "/FileName");
     // ファイル確認処理 or ...
     return new Bitmap(filename);
}
// ...

// 使用時
class Sample
{
    int Location;
    string Name;
    Bitmap Image;

    static Sample Read(string filename)
    {
        ConfigurationXmlReader cxr = new ConfigurationXmlReader(filename);
        cxr.Load();
        Sample s = new Sample();
        
        s.Location = cxr.GetInt("Sample/Location");
        s.Name = cxr.GetName("Sample/Name");
        s.Image = cxr.GetBitmap("Sample/Image");
        
        return s;
    }
}




で、この作ったConfiurationXmlReader / Writer が非常に使いやすくなったので、いろいろ調整した後にこのクラスをもっと再利用可能な形まで作り上げて配布なりをしようと思っていました。

で、ソフトを作ってくとちゅうでアプリケーションの設定ファイルというものが必要になりました、インストールされているプラグイン・スキン等のリストを保存しているファイルです、これも後でいじれるようにするためにXml形式を利用したいと思いました。

そこで、まえ作ってあったConfigurationXmlXXXXXクラス(Reader / Writer)を改造してそれを使って読み込もうと思いました(ConfigurationXmlXXXXXクラスの発展のため)そこでリスト形式のデータを読み込むメソッド GetList<T> を作ろうと思ったのですが、仕組みを見てわかるとおりConfigurationXmlでは string / int / double / bool ...etc などのベースとなるメソッドを呼び出すことによってあとから Size / Rectangle / Point / Bitmap / Font ... などの複雑なものや自分で定義した構造体・クラスを読み込めるコードを書いていっています。そこで下記のようなコードが組めればコードがすっきりすると思い書いてみたんですが、Tとstring / int / double 等のキャストができないとエラーを吐いてだめでした(よって実行していないからそこ以外の部分も間違いがあるかもしれない)

コード:
List<T> GetList<T>(string xpath)
{
    List<T> list = new List<T>();
    
    XmlNode parentNode = xmlDocument.SelectSingleNode(xpath);    

    List<T> list = new List<T>();

    foreach(XmlNode node in parentNode.ChildNodes)
    {

        if(typeof(T) == typeof(string))
        {
            list.Add((T)GetString(node.BaseURI));
        }
        else if(typeof(T) == typeof(int))
        {
            list.Add((T)GetInt(node.BaseURI));
        }
        // ...
    }
    return list;
}



僕としてはConfigurationXmlXXXXXでリスト程度読み込めるようになりたかったんですが、設定の保存ができないと先に進めなかったんで、とりあえず今は設定の保存はXmlSerializerでまかなえるので(Bitmap等のデーターは設定のクラスには含まれていないため)XmlSerializerで設定はファイルは保存します。

っということです、アプリケーション的にはこれでまったく問題ないんですが、拡張性とかを考えるとConfigurationXmlXXXXXをちゃんと作りたかったのでここに質問させていただきました。

説明が下手糞なんでわからないところとか変なところあったら突っ込んでください(笑。


_________________
有末 清華
crazy(){for;;{you();}} - プログラマの覚書
1

スキルアップ/キャリアアップ(JOB@IT)