none
プログラムで変数を定義したい RRS feed

  • 質問

  • 普通、変数は以下のように直接書いて定義しますが、

     

    Code Snippet
    string name;

     

    プログラム上で好きなように定義することは C# で可能なのでしょうか?


     

    例えば、ある関数の引数として付けたい変数名を渡します。すると、その関数
    内では、受け取った文字列を名前とする変数を定義する、ということが可能な
    のでしょうか?


    Code Snippet
    private void create_variable (string name)
    {
      "name" を名前とする変数生成
    }

     

    別な言語、例えば、javascript や php では以下のようにして変数を作ること
    が可能です。C# では何らかの手段があるのでしょうか?

     

    Code Snippet

    javascritp

      objectX[name] .... objectX の中に name の値を名前とする変数が生成される

     

    php

      ${$name} .......... name の値を名前とする変数が生成される

     

    2008年2月7日 4:37

回答

  • 連想配列で何か問題があるでしょうか?

    .NET では Hashtable(.NET 2.0 以降では Dictionary<TKey, TValue> も使えます)が連想配列ですが。

    2008年2月7日 5:07

すべての返信

  • 連想配列で何か問題があるでしょうか?

    .NET では Hashtable(.NET 2.0 以降では Dictionary<TKey, TValue> も使えます)が連想配列ですが。

    2008年2月7日 5:07
  • あぁ、そうでした。連想配列があった。

    連想配列で全く問題ありません。

    1ヶ月前に試しただけだったので、忘れてました。

     

    Hongliang さん、ありがとうございます。

     

     

    他にもありますかね? お気づきの方はお教えください。

    取り敢えず、本件は閉じます。

    2008年2月7日 5:32
  • Code Snippet

    public partial class Form1 : Form
    {
      private string name = "ahaha"; ---+
                                        |
      public Form1()                    |
      {                                 |
        InitializeComponent();          |
                                        |
        string s = "name"; <------------+
        string v = this.getField(s); // "ahaha"

        MessageBox.Show(v);

      }

     

      public string getField(string str)
      {
        return (string)GetType().InvokeMember(
          str,
          System.Reflection.BindingFlags.Instance
            | System.Reflection.BindingFlags.NonPublic
            | System.Reflection.BindingFlags.GetField,
          null,
          this,
          null);
      }
    }

     


    現状理解できてなけど、
    変数名を指定すると、その変数名をもつ private field の値を取得できる。

    2008年2月17日 17:11
  • 外池と申します。

     

    例えばですね、ユーザーが、1)対話形式でいろいろなデータが入力し、かつ、ユーザーがそのデータに名前(変数名)をつける、さらに、2)ユーザーがその名前(変数名)を使って処理の方法を指定するから、それに従って処理する。このような機能を持つプログラムを作ろうとされているのであれば、1)の部分でデータとその名前(変数名)を関連付けるために「連想配列」(Dictionary)が必要でしょう。2)の部分については、まったく別の検討をしないといけないのでここでは省略します。

     

    次に、

     

    最後に例示されたプログラムですが、考え方として、

    • まず、通常の書き方をしたプログラムがあることが大前提です。つまり、変数名が固定されているわけです。
    • その上で、変数名が入った文字列型データを使って、その変数を呼び出す機能がある。

    ということです。もう少し一般的に書きますと、

    • 固定の名前を持つメンバー(変数、メソッド、プロパティー)に対して、文字列型データを使ってメンバーを呼び出すことができるわけですが、
    • だからといって、プログラムが自分自身に任意の名前を使ってメンバーを加える機能はありません。
    2008年2月18日 0:52
  • 外池 さん、コメントありがとうございます。

     

     外池 さんからの引用

    例えばですね、ユーザーが、


    1)対話形式でいろいろなデータが入力し、かつ、ユーザーがそのデータに名前(変数名)をつける、


    さらに、


    2)ユーザーがその名前(変数名)を使って処理の方法を指定するから、それに従って処理する。


    このような機能を持つプログラムを作ろうとされているのであれば、
    1)の部分でデータとその名前(変数名)を関連付けるために「連想配列」
    (Dictionary)が必要でしょう。


    2)の部分については、まったく別の検討をしないといけないのでここでは省
    略します。


    今回は、2) が近いと思います。


     外池 さんからの引用

    最後に例示されたプログラムですが、考え方として、
    まず、通常の書き方をしたプログラムがあることが大前提です。


    まさしくその通りです。本当に狙っている変数は決まった名前をしています。
    但し、決まった命名規則に従っているだけです。テーブル名と "DataGridView"
    をくっつけた名前です。例えば、columnsDataGridView。


     

     

    そもそも、こんな質問をした切っ掛けは、


    DataGridView とボタン等のコントロールを含む UserControl が沢山あり、
    それらには共通した動作を定義しているので、
    ベースとなる UserControl を抽象化しようとしましたが、


    デザイナを使って DataGridView を作成すると、Designer.cs に DataTable に
    応じた名前の BindingSource や DataSet が自動的に作成されるので、抽象化
    しにくいなぁ、となりました。

    # DataGridView の Name を固定化すれば、それらの名前も固定化できますが、
    # それを入力するのが面倒なので、半自動化したいと考えていました。


    しかも、UserControl 上に置いた DataGridView は、
    配置した UserControl 上ではサイズや位置を変更可能ですが、
    UserControl 自体を別 Form などに置いてしまうと、
    その内部にある DataGridView の位置やサイズをデザイナから扱うことはできません。


    Form 上の UserControl に含まれる DataGridView の位置やサイズを扱う方法
    があるのなら、是非それも知りたいと思っています。
    # 別スレッドとして挙げます


    それで、その位置やサイズが個々に違うため、更に抽象化しにくいと感じて

    しまいました。


    という訳で、デザイナを使って内包するコントロールの位置やサイズを指定で
    きるような UserControl を抽象化する方法を知らないので、

    それならば、
    UserControl 自体にはそのインスタンスごとの内部変数を引数とするメソッド
    を作るのみにしようと考えました。


    それで、
    インスタンスごとの内部変数名は DataTable 名と "DataGridView" などの命名
    規則が決まっているので、それから参照先を取ってこようと考えた次第です。

     

    UserControl 上の DataGridView の位置やサイズをデザイナで変更できる

    抽象化された UserControl を作れれば解決なのかもしれません。

     


     外池 さんからの引用

    だからといって、プログラムが自分自身に任意の名前を使ってメンバーを加え
    る機能はありません。


    了解。

    2008年2月18日 2:52
  • 外池です。整理させてください・・・。

    • 抽象化した(というか、より一般化した、という感じ?)新しいUserControlの中にはDataGridViewを置く。
    • そのUserControlは、いろんなFormに貼り付けたい。アプリでは、そのいろんなFormが同時に使われる。
    • で、親のFormからの指示によるか、対等なForm同士の指示によるかはわかりませんが、Formの外からFormのメソッドを呼び出すか、プロパティーを設定するかして、UserContorolの中のDataGridViewの配置等の外観を変更(カスタマイズ)したい。

    ということでしょうか? であれば・・・、

    • ものすごく荒っぽいけれども、簡単にできる方法がひとつ、UserControlの中のDataGridViewのようなコントロールは全部Publicにする。で、そのUserContorolもPublicでFormに貼り付ける。そうすれば、Form->UserControl->DataGridViewとアクセスできて、DataGridViewの外観は直接変更できるのでは?
    • で、基本的に同じ考え方ですが、全部Publicにして丸見え状態を避けるためにコントロールはPrivateにして、変わりに、変更を加えたい項目だけを外部から設定できるように独自のPropertyを作ってやるのも良いかと。

    しかし・・・、

     

    このような外観の調整は、アプリのコーディング(デザイン)の段階で行えばよいのでしょうか? それとも、アプリの実行中にダイナミック行う必要がありますか?

     

    >>2)ユーザーがその名前(変数名)を使って処理の方法を指定するから、それに従って処理する。

    >今回は、2) が近いと思います。

     

    気になるのは、外観の調整の元になる「処理の方法の指定」は、どれぐらい複雑なものになりますか? あるいはバリエーショの多さはどれぐらいですか? (オプションがいくつかある中から選ぶ程度なのか、数式やミニ言語を使わないといけないようなものか)

    2008年2月18日 4:09
  • 外池 さん、サポートありがとうございます。


    詳細は次のコメントで行うとして、今対処している点を書きます。

    サンプルも後ほど用意します。


     外池 さんからの引用

    ものすごく荒っぽいけれども、簡単にできる方法がひとつ、


    UserControl の中の DataGridView のようなコントロールは全部 Public にする。
    で、その UserContorol も Public で Form に貼り付ける。
    そうすれば、Form->UserControl->DataGridView とアクセスできて、
    DataGridView の外観は直接変更できるのでは?

     

    で、基本的に同じ考え方ですが、
    全部 Public にして丸見え状態を避けるためにコントロールは Private にして、
    変わりに、

    変更を加えたい項目だけを外部から設定できるように独自の Property を作ってやるのも良いかと。


    ちょうどこちらでも調べて、多分同じ方法に行き着いてます。
    別スレッドに結果を書いてます。

    プロパティのみ public です。

     

    - Form を開いたデザイナで、Form に配置された UserControl 上の DataGridView のプロパティを変更したい

     

    2008年2月18日 5:01
  • Form に配置されてしまった UserControl 内の DataGridView はデザイナ上で
    触れない、とさっきまで思ってたので、どうやって BindingSource (DataSet)
    を UserControl 間で (楽に) 共有させようか、と悩んでましたが、


    Form 上の UserControl 内 DataGridView もデザイナからアクセス可能という
    ことが分かったので、ちょっと楽になりました。


    触れなかった理由が DataGridView が単に private になってただけだったとは。

     

    ここで、一旦サンプルを提示します。


    - ダウンロード : ソース
    - 確認 : 画像

     

    このサンプルでは、Form にあらかじめ関連付けした BindingSource を組み込
    ませ、各 DataGridView の DataSource にそれらを割り当てていますので、親
    DataGridView の選択を変えると、子 DataGridView の内容が変更されるように
    なっています。


    これは期待通りです。

     

     

     

    で、続いて、DataGridView 右下に置いている Save ボタンで保存をやろうと思
    います。このボタンを押して実行されるイベント ハンドラ saveButton_Click()
    をどう実装するか迷っています。

     

    DataGridView を Form にドラッグした際一緒に作成される BindingNavigator
    の SaveItem ボタンのイベント ハンドラは以下のように記述されています。


    Code Snippet
    private void columnsBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
      this.Validate();
      this.columnsBindingSource.EndEdit(); ......................................... (1)
      this.tableAdapterManager.UpdateAll(this.syllabaryDataSet); ................... (2)
    }

     

    このような一連の処理が推奨なのでしょうから、そのようにしますが、(1) の
    BindingSource は各 UserControl で異なりますから DataGridView.DataSource
    に代入されたもので代用します。


    で、(2) の TableAdapter は ...... UserControl にはない。現状
    UserControl には空っぽの DataGridView と Button を置いてるだけなので、
    TableAdapter はありません。

     

    Code Snippet

    private void saveButton_Click(object sender, EventArgs e)
    {
      this.Validate();

      ((BindingSource)this.dataGridViewEx.DataSource).EndEdit();

      ???
    }

     


    サンプルでは TableAdapter は Form 上にあります。(2) を実行させるために、

    1. Form の TabaleAdapter を UserControl に取り込むか、
    2. Form にデータ保存を受け持つメソッドを作り、UserControl から this.Parent.メソッド() として保存を任せるか、
    3. UserControl にあらかじめ TableAdapter を含ませておくか、

    などなど考えていますが、どれが最も適当なのか判断しかねています。

    そんな場合は、こうすればいい、という意見がありましたら、お教えください。

     

     

    仮に UserControl を使わず親と子の Save ボタンで別々なメソッドを使うなら、
    次のようになるのかもしれません。やってることは違わないけど、対象が異なる。
    これを 1つにまとめておきたい。


    Code Snippet

    private void columnsBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
      this.Validate();
      this.columnsBindingSource.EndEdit();
      this.columnsTableAdapter.Update(this.syllabaryDataSet.columns);
    }

     

    private void charsBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
      this.Validate();
      this.charsBindingSource.EndEdit();
      this.charsTableAdapter.Update(this.syllabaryDataSet.chars);
    }

     

    2008年2月18日 10:18
  •  外池 さんからの引用

    このような外観の調整は、

    アプリのコーディング(デザイン)の段階で行えばよいのでしょうか? 
    それとも、
    アプリの実行中にダイナミック行う必要がありますか?


    "外観の調整" は、見掛けに凝ってませんので、実行中に行うほどのことではな
    いとおもいます。単にサイズと位置を合わせるだけです。それも固定状態。


     外池 さんからの引用

    気になるのは、
    外観の調整の元になる「処理の方法の指定」は、どれぐらい複雑なものになりますか?


    "外観の調整の元になる「処理の方法の指定」" というのがよく分かりませんが、
    UserControl で変更するプロパティのことと解釈して話すと、

    • DataGridView の Height, Width
    • DataGridView の Column の表示非表示
    • DataGridView の ColumnHeaderText の書き換え

    だけです。


     外池 さんからの引用

    あるいは
    バリエーショの多さはどれぐらいですか?


    バリエーションはありません。数が多いだけです。数が多いといっても7個しか
    ありませんが、定型作業なので、後のメンテナンスも考えて、抽象化できたら、
    しておきたいと考えています。

    2008年2月18日 10:28
  •  custar さんからの引用

    "外観の調整" は、見掛けに凝ってませんので、実行中に行うほどのことではないとおもいます。単にサイズと位置を合わせるだけです。それも固定状態。

     

    なるほど。プログラムの実行中に変更する必要がないのであれば、デザイン時にプロパティーで調整できる程度の作りこみが、全体として扱い易いでしょう。

     

     custar さんからの引用

    "外観の調整の元になる「処理の方法の指定」" というのがよく分かりませんが、UserControl で変更するプロパティのことと解釈して話すと、

    • DataGridView の Height, Width
    • DataGridView の Column の表示非表示
    • DataGridView の ColumnHeaderText の書き換え

    だけです。

     

    いえ、これは、私の勝手な想像で、製作されているUserControlの機能もだし、表示のバリエーションを決める条件の記述がものすごく複雑なのか、と思っていたのです。例えば、複数の変数名を使って数式を入力したら、変数名ごとの値を表す表に、さらに、数式の演算をステップ実行させるボタンが現れる・・・、というような。(ほとんど妄想に近いですよね。) ま、これは、忘れてください。


     custar さんからの引用

    バリエーションはありません。数が多いだけです。数が多いといっても7個しかありませんが、定型作業なので、後のメンテナンスも考えて、抽象化できたら、しておきたいと考えています。

     

    やはり、今の線での作業でよろしいのではないかと思います。

    2008年2月18日 12:41
  • それぞれの動作をもつ UserControl に分けるのは、メンテナンスを考えるとい
    いとしても、情報の共有という点ではかなり面倒なことになるなぁ、と感じて
    きました。


    素の DataGridView の使い勝手をそのままにしておきたいので、UserControl
    内に閉じ込めるのは止めた方がいいと考え始めています。


    検討し直してみます。外池 さん、サポートありがとうございます。

    2008年2月19日 3:38