変数へのコードの割り当て


124

変数を作成し、それにコード行を割り当てることは可能ですか?

ButtonClicked = (MessageBox.Show("Hello, World!"));

...したがって、変数を使用すると、コード行が実行されます。


100
コーディングの初心者と良い質問をするというまれな組み合わせの+1:あなたは何をしたいのかを理解し、それをうまく説明します、あなたはそれを自分で見つけることができないので、その用語がわからないだけです。
Tim S.

10
あなたが探している用語はデリゲートです。
ラッセV.カールセン2014

stackoverflow.com/questions/6187944/…これを確認してください。必要な説明は十分にあると思います。その点では、ASPはほぼwinformsのように機能します。
CSharpie 2014

Objective-cのブロックのように聞こえる
ブライアントレーシー

回答:


89

次のActionように割り当てることができます。

var ButtonClicked = new Action(() => MessageBox.Show("hi"));

次に、それを呼び出します:

ButtonClicked();

完全を期すために(さまざまなコメントに関して)...

Erikが述べたように、複数行のコードを実行できます。

var ButtonClicked = new Action(() =>
{
    MessageBox.Show("hi");

    MessageBox.Show("something else");  // something more useful than another popup ;)
});

ティムが述べたように、Actionキーワードを省略できます

Action ButtonClicked = () => MessageBox.Show("hi");

Action ButtonClicked = () =>
{
    // multiple lines of code
};

空の括弧に関するKRyanのコメントに対処するには、アクションに送信できるようにするパラメーターのリスト(この場合はなし)を表します。

たとえば、表示するメッセージを指定したい場合は、「メッセージ」をパラメーターとして追加できます 単一の文字列パラメーターを指定するためにに変更Action ことに注意してください)Action<string>

Action<string> ButtonClicked = (message) => MessageBox.Show(message);

ButtonClicked("hello world!");

10
Action ButtonClicked = () => MessageBox.Show("hi");同等でIMOの方が適切です(必要に応じて括弧を追加します)
Tim S.

1
アクションが複数行のコードに解決される可能性もあります。
エリックフィリップス

2
@CSharpieその仮定を行うことがOPに役立つかどうかはわかりません。
エリックフィリップス

2
@CSharpieなぜOPはこれを使用できなかったのWinFormsですか?
vivat pisces 2014

2
@CSharpie私はあなたが言っていることを見ます。これを実際にButton.Clickイベントにアタッチしていて、たまたま名前を付けた変数に格納していない場合ButtonClicked
vivat pisces 2014

51

あなたのケースでは、あなたが使用したいと思いますdelegate

デリゲートがどのように機能するか、そしてその概念を理解することによってどのようにしてより簡単なフォームに到達できるかを見てみましょう。

// Create a normal function
void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();

ご覧のとおり、デリゲートは通常の関数の形式をとっていますが、引数はありません(他のメソッドと同じように引数をいくつでも取ることができますが、簡単にするために取りません)。

さて、私たちが持っているものを使ってみましょう。他の変数を定義するのと同じようにデリゲートを定義します。

ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);

基本的に、ButtonClickedと呼ばれる新しい変数を作成しました。これは、ButtonClick(デリゲート)のタイプを持ち、使用すると、OnButtonClick()メソッドのメソッドを実行します。
これを使用するには、次のコードを呼び出すだけです。ButtonClicked();

したがって、コード全体は次のようになります。

delegate void ButtonClick();

void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}

void Foo()
{
    ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
    ButtonClicked(); // Execute the function.
}  

ここから、ラムダ式に移動して、それらがあなたの状況でどのように役立つかを確認できます:
.NETライブラリによってすでに定義されている多くのデリゲートがあり、アクションなど、パラメーターを受け入れず、値を返しません。以下のように定義されたpublic delegate void Action();
あなたは常にあなたのニーズの代わりに、新しいデリゲートを毎回定義する必要があるため、それを使用することができます。たとえば、前のコンテキストでは、次のように書くことができます

Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();

同じことをしたでしょう。
デリゲートのさまざまな使用方法を確認したので、最初のラムダ式を使用してみましょう。ラムダ式は無名関数です。したがって、これらは通常の関数ですが、名前はありません。それらはそれらの形式のものです:

x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");

この場合、パラメーターがないため、最後の式を使用します。これはOnButtonClick関数と同じように使用できますが、名前付き関数がないという利点があります。代わりに次のようなことができます:

Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );

またはさらに簡単に、

Action ButtonClicked = () => MessageBox.Show("Hello World!");

次に、単に呼び出しますButtonClicked();。もちろん、複数行のコードを使用することもできますが、これ以上混乱させたくありません。ただし、次のようになります。

Action ButtonClicked = () => 
{
    MessageBox.Show("Hello World!");
};
ButtonClicked();

たとえば、次のような関数を実行することもできます。

new Action(() => MessageBox.Show("Hello World!"))();

長い投稿でごめんなさい、あまり混乱しないことを願っています:)

編集:私は、頻繁には使用されない場合でも、ラムダ式を理解しやすくすることができる別の形式について言及するのを忘れていました:

new Action(delegate() {
    Console.WriteLine("I am parameterless");
})();

また、ジェネリックを使用する:

// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.
new Action<string>(delegate(string x) {
    Console.WriteLine(x);
})("I am a string parameter!");

次にラムダ式を使用できますが、パラメーターのタイプを定義する必要はありません(ただし場合によっては)、たとえば、上記のコードは次のように簡単に記述できます。

new Action<string>(x => {
    Console.WriteLine(x);
})("I am a string parameter!");

または:

new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");

EDIT2:
Action<string>はの表現public void delegate Action(string obj);
Action<string,string>はの表現public void delegate Action(string obj, string obj2);
一般的に、Action<T>public void delegate Action<T>(T obj);

EDIT3:私は投稿がしばらくここにあることを知っていますが、これは言及しないのは本当にクールだと思います:あなたはこれを行うことができますが、これは主にあなたの質問に関連しています:

dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");

または単に:

Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");

7

このLazyクラスは、ユーザーが要求するまで計算されない値を表すように特別に設計されています。構築方法を定義するメソッドを提供することでそれを構築しますが、そのメソッドの実行は1回しか処理せず(値を要求する複数のスレッドに直面した場合でも)、追加の要求に対してすでに構築された値を返すだけです。

var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));

var result = foo.Value;

それを忘れないでくださいLazy多くの処理能力を必要とする値に使用されなければならない、と(の意味があるため、あなたが相互作用のためにそれらを使用するべきではないこと.Value、それは財産ではなく、(インタラクティブ)アクションに同様の値を返すということです)。代わりに、デリゲートをそのようなアクションに使用する必要があります。
アベル

1
@Abelいいえ、それは多くの処理能力を必要とする値ではなく、要求されるまで初期化を延期したい値であり、その値を2回以上初期化することはありません。ここではの値Value 使用されます。それがされたDialogResultメッセージボックスを表示から受け取りました。このソリューションとデリゲートの主な違いは、値が要求されるたびに値を再計算する必要があるかどうかです。要件の私の解釈は、これは概念的に値を初期化することであり、繰り返される操作ではないというものでした。
サービー2014

Lazy簡単に誤って使用することができます。それ自体のオーバーヘッドがあり、小さなタスクを延期するために「ただ」それを使用すると、得られるよりも多くのオーバーヘッドが呼び出されます。プロパティに関係なくメッセージボックスを表示することは、(imo)に関係なく、一般に悪い習慣ですLazy。ところで、MSDNから引用すると、「遅延初期化を使用して、大きなオブジェクトやリソースを大量に消費するオブジェクトの作成を延期する」とのことです。あなたはそれに同意することはできませんが、それはそれが最初に設計されたものでした。
アベル

1
@AbelこのLazyようなコンテキストでのパフォーマンスのオーバーヘッドは無視できます。人間がメッセージボックスをクリックするのを待つのに費やした時間と比較すると、見た目が悪くなります。これは主に、基盤となるアプリケーションの実際の要件に起因します。質問の曖昧さは客観的に正しい答えを不可能にします。これは質問の解釈の1つです。プロパティゲッターで多くの作業を行うのは悪いことです。どうやらあなたは根本的にのデザイン全体に反対していますLazy。あなたはその意見を歓迎します。
サービー2014

すみません、私を誤解したに違いありません。確かにMessageBox 、オーバーヘッドはごくわずかです(私はプロパティ内でUIを使用しません)。私は一般的に小さなタスク(deferringなど2 + 3 * 4 / i)を意味し、クロージャーを作成するオーバーヘッドは計算自体よりも大きくなります。そして、私は完全に受け入れていると思います。Lazy実際には、F#で多く使用します(C#では少し少ないです)。パフォーマンスに関して。
アベル

4

私があなたの質問を読んでいる方法、これはGUIコントロールのコンテキストにありますか?

これがWPFにある場合は、コントロールからのコマンドを処理する「正しい」方法を確認してください。http//msdn.microsoft.com/en-us/library/ms752308(v = vs.110).aspx

...しかし、それは苦痛とやり過ぎになる可能性があります。より単純な一般的なケースでは、次のようなイベントハンドラーを探している可能性があります。

myButton.Click += (o, e) => MessageBox.Show("Hello, World!");

そのイベントハンドラーは、さまざまな方法で処理できます。上記の例では無名関数を使用していますが、次のようにすることもできます。

Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);

...あなたが求めていたのと同じように、変数として割り当てられた関数(またはここではvoidを返すので「アクション」)を使用します。


1

C#コードを変数に割り当て、実行時にコンパイルしてコードを実行できます。

  • コードを書く:

    // Assign C# code to the code variable.
    string code = @"
    using System;
    
    namespace First
    {
        public class Program
        {
            public static void Main()
            {
                " +
                "Console.WriteLine(\"Hello, world!\");"
                + @"
            }
        }
    }
    ";
  • プロバイダーのプロバイダーとコンパイラーのパラメーターを作成します。

    CSharpCodeProvider provider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters();
  • コンパイラーのパラメーターを定義します。

    // Reference to System.Drawing library
    parameters.ReferencedAssemblies.Add("System.Drawing.dll");
    // True - memory generation, false - external file generation
    parameters.GenerateInMemory = true;
    // True - exe file generation, false - dll file generation
    parameters.GenerateExecutable = true;
  • アセンブリをコンパイルします。

    CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
  • エラーを確認します。

    if (results.Errors.HasErrors)
    {
            StringBuilder sb = new StringBuilder();
    
            foreach (CompilerError error in results.Errors)
            {
                    sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
            }
    
            throw new InvalidOperationException(sb.ToString());
    }
  • アセンブリ、タイプ、およびMainメソッドを取得します。

    Assembly assembly = results.CompiledAssembly;
    Type program = assembly.GetType("First.Program");
    MethodInfo main = program.GetMethod("Main");
  • それを実行します:

    main.Invoke(null, null);

参照:

http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime


動的なコードのコンパイルが質問にまったく関連していないと思います。
Iravanchi 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.