web-dev-qa-db-ja.com

C#-Winforms-グローバル変数

私はいくつかの変数がプロジェクト全体でグローバルであり、すべての形式でアクセス可能であることを望んでいます。これどうやってするの?

27
Moon

はい、静的クラスを使用してできます。このような:

static class Global
{
    private static string _globalVar = "";

    public static string GlobalVar
    {
        get { return _globalVar; }
        set { _globalVar = value; }
    }
}

そして、あなたが書くことができる場所を使うために:

GlobalClass.GlobalVar = "any string value"
76
Wael Dalloul

または、グローバルを app.config に入れることもできます

6
Rigobert Song

静的クラス または シングルトンパターン を使用できます。

5
Michał Ziober

一方通行、

ソリューションエクスプローラー>プロジェクト>プロパティ> Settings.Settings。このファイルをクリックして、IDEから設定の定義を追加します。

にアクセスする

Properties.Settings.Default.MySetting = "hello world";
4
Steve

ここでのコンセンサスは、グローバル変数を静的メンバーとして静的クラスに入れることです。新しいWindowsフォームアプリケーションを作成すると、通常、プログラムクラス(Program.cs)が付属します。これは静的クラスであり、アプリケーションのメインエントリポイントとして機能します。アプリの存続期間全体にわたって有効であるため、新しい変数を作成するのではなく、グローバル変数をそこに配置するのが最善だと思います。

static class Program
{
    public static string globalString = "This is a global string.";

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

そして、次のように使用します:

public partial class Form1 : Form
{
    public Form1()
    {
        Program.globalString = "Accessible in Form1.";

        InitializeComponent();
    }
}
public static class MyGlobals
{
  public static string Global1 = "Hello";
  public static string Global2 = "World";
}

public class Foo
{

    private void Method1()
    {
       string example = MyGlobals.Global1;
       //etc
    }
}
2
user138894

彼らはすでにグローバル変数の使用方法に答えています。

スペイン語のstackoverflowで実行される question の結果、グローバル変数の使用が悪い考えである理由を説明します。

スペイン語のテキストの明示的な翻訳:

変更の影響

グローバル変数の問題は、隠された依存関係を作成することです。大規模なアプリケーションに関しては、自分自身が知らない/覚えていない/自分が持っているオブジェクトとその関係についてはっきりしている。

そのため、グローバル変数が使用しているオブジェクトの数を明確に把握することはできません。そして、たとえば、可能性のある各値の意味やタイプなど、グローバル変数の何かを変更したい場合は?その変更は何個のクラスまたはコンパイル単位に影響しますか?金額が少ない場合は、変更する価値があります。影響が大きい場合は、別のソリューションを探す価値があるかもしれません。

しかし、その影響は何ですか?グローバル変数はコード内のどこでも使用できるため、測定するのは非常に困難です。

さらに、変数を使用するコードの量が可能な限り少なくなるように、可能な限り短いライフタイムの変数を常に使用するようにしてください。したがって、その目的と変更者をよりよく理解します。

グローバル変数はプログラムの期間中持続するため、だれでも変数を使用して読み取り、さらに悪いことにその値を変更することができ、特定のプログラムで変数がどのような値を持つかを知ることがより困難になりますポイント。 。

破壊の順序

別の問題は破壊の順序です。変数は、ローカル変数またはグローバル/静的変数であるかどうかにかかわらず、常に作成の逆の順序で破棄されます(例外はプリミティブ型、intenumsなどです。それらはプログラムを終了するまでグローバル/静的です)。

問題は、グローバル(または静的)変数の構築順序を知ることが難しいことです。原則として、それは不確定です。

すべてのグローバル変数/静的変数が単一のコンパイル単位にある場合(つまり、.cppのみ)、構築の順序は書き込みの順序と同じです(つまり、以前に定義された変数が構築されます)前)。

しかし、それぞれが独自のグローバル/静的変数を持つ複数の.cppがある場合、グローバルな構築順序は不確定です。もちろん、各コンパイル単位(各.cpp)の順序は特に尊重されます。グローバル変数ABAの前に定義されている場合Bの前に構築されますが、他の.cppAB変数の間で初期化される可能性があります。たとえば、次のグローバル/静的変数を持つ3つのユニットがある場合:

Image1

実行可能ファイルでは、この順序で(または各.cpp内で相対的な順序が守られている限り、他の順序で)作成できます。

Image2

何でこれが大切ですか?異なる静的グローバルオブジェクト間にリレーションがある場合、たとえば、一部のデストラクタで、他のグローバル変数のデストラクタで他のオブジェクトを使用する場合、すでに破棄されていることが判明した別のコンパイルユニットの別のグローバルオブジェクトを使用するため後で構築されます)。

非表示の依存関係と*テストケース*

この例で使用するソースを見つけようとしましたが、見つかりません(とにかく、例はグローバル変数と静的変数に適用できますが、シングルトンの使用を例示するためでした)。非表示の依存関係は、グローバル変数の状態に依存する場合、オブジェクトの動作の制御に関連する新しい問題も作成します。

支払いシステムがあり、変更を加える必要があり、コードが他の人(または数年前のもの)のものであるため、支払いシステムをテストして、どのように機能するかを想像してください。新しいmainを開き、銀行支払いサービスにカードを提供するグローバルオブジェクトの対応する関数を呼び出します。すると、データを入力すると請求されます。簡単なテストで、製品版をどのように使用しましたか?簡単な支払いテストを行うにはどうすればよいですか?

他の同僚に尋ねた後、収集プロセスを開始する前に、テストモードにあるかどうかを示すグローバルブールである「true」をマークする必要があることがわかりました。支払いサービスを提供するオブジェクトは、支払い方法を提供する別のオブジェクトに依存し、その依存関係はプログラマーには見えない方法で発生します。

言い換えれば、グローバル変数(またはシングルトーン)は、「テスト」インスタンスに置き換えられないため、「テストモード」に渡すことを不可能にします(コードが作成または定義されているコードを変更しない限り)。グローバル変数ですが、テストはマザーコードを変更せずに行われると想定しています)。

解決

これは、*依存性注入*と呼ばれるものによって解決されます。これは、オブジェクトがコンストラクターまたは対応するメソッドで必要とするすべての依存性をパラメーターとして渡すことにあります。このように、プログラマーはコードを記述しなければならないため、開発者が多くの時間を稼ぐことができるので、**自分に何が起きなければならないのかを理解します。

グローバルオブジェクトが多すぎて、それらを必要とする関数のパラメーターが多すぎる場合は、「グローバルオブジェクト」のインスタンスを構築して返すクラス*スタイル*ファクトリ*に「グローバルオブジェクト」をいつでもグループ化できます。 "(シミュレートされた)必要に応じて、ファクトリをパラメーターとして、グローバルオブジェクトを依存関係として必要とするオブジェクトに渡します。

テストモードに渡す場合は、常にテストファクトリ(同じオブジェクトの異なるバージョンを返す)を作成し、ターゲットクラスを変更せずにパラメーターとして渡すことができます。

しかし、それは常に悪いですか?

必ずしも、グローバル変数の適切な使用法があるとは限りません。たとえば、定数値(PI値)。定数値であるため、プログラム内の特定のポイントで、別のモジュールからの任意のタイプの変更によってその値を知らないというリスクはありません。さらに、定数値はプリミティブになる傾向があり、その定義を変更することはほとんどありません。

この場合、グローバル変数を使用すると、変数をパラメーターとして渡す必要がなくなり、関数のシグネチャが簡素化されます。

もう1つは、ログクラス(通常はオプションであり、プログラムで構成可能であり、したがってアプリケーションの核の動作に影響を与えないファイルで発生することを保存する)などの非侵入型の「グローバル」サービス、またはstd :: coutstd :: cinまたはstd :: cerr。これらもグローバルオブジェクトです。

他のものは、たとえその寿命がプログラムの寿命とほぼ一致していても、常にパラメーターとして渡します。変数はモジュール内でグローバルであり、他のアクセス権を持たない場合にのみ可能ですが、いずれにしても、依存関係は常にパラメーターとして存在します。

回答: Peregring-lk

1
J. Rodríguez

Visual C#を使用している場合、行う必要があるのは、Formを継承するProgram.csにクラスを追加し、すべてのForm * .csですべての継承クラスをFormから自分のクラスに変更することだけです。

//Program.cs
public class Forms : Form
{
    //Declare your global valuables here.
}

//Form1.cs
public partial class Form1 : Forms    //Change from Form to Forms
{
    //...
}

もちろん、 クラスFormを変更せずに拡張する にする方法があります。その場合は、拡張するだけです!すべてのフォームがデフォルトで継承しているため、その中で宣言されているすべての貴重品は自動的にグローバルになります!幸運を!!!

0
user8931966