변수를 만들고 다음과 같은 코드 줄을 할당 할 수 있습니까?
ButtonClicked = (MessageBox.Show("Hello, World!"));
... 변수를 사용하면 코드 줄이 실행됩니다.
변수를 만들고 다음과 같은 코드 줄을 할당 할 수 있습니까?
ButtonClicked = (MessageBox.Show("Hello, World!"));
... 변수를 사용하면 코드 줄이 실행됩니다.
답변:
다음 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 ;)
});
Tim이 말했듯이 Action
키워드를 생략 할 수 있습니다.
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
KRyan의 주석을 처리하기 위해 비어있는 괄호와 관련하여 Action에 보낼 수있는 매개 변수 목록을 나타냅니다 (이 경우에는 없음) .
예를 들어 표시 할 메시지를 지정하려는 경우 "message"를 매개 변수로 추가 할 수 있습니다 ( 단일 문자열 매개 변수를 지정하기 위해로 변경 Action
했습니다 ) .Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
Action ButtonClicked = () => MessageBox.Show("hi");
동등하고 IMO가 더 좋습니다 (원하는 경우 괄호 추가)
WinForms
없습니까?
Button.Click
이벤트에 첨부 하고 그가 이름을 지정한 변수에 저장하지 않는다면 ButtonClicked
.
귀하의 경우에는 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);
기본적으로 ButtonClick (대리자) 유형을 갖는 ButtonClicked라는 새 변수를 만들었으며 사용시 OnButtonClick () 메서드에서 메서드를 실행합니다.
이를 사용하려면 다음을 호출하면됩니다.ButtonClicked();
따라서 전체 코드는 다음과 같습니다.
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
여기에서 람다 식으로 이동하여 상황에서 유용 할 수있는 방법을 확인할 수 있습니다.
.NET 라이브러리에 의해 이미 정의 된 많은 대리자가 있으며 일부는 매개 변수를 허용하지 않고 값을 반환하지 않는 Action과 같습니다. 과 같이 정의된다 public delegate void Action();
당신은 항상 새로운 위임마다 정의의 필요성 대신 여러분의 필요에 사용할 수 있습니다. 예를 들어 이전 컨텍스트에서 방금 작성했을 수 있습니다.
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
같은 일을했을 것입니다.
이제 대리자를 사용하는 다양한 방법을 보았으므로 첫 번째 람다 식을 사용하겠습니다. Lambda 표현식은 익명 함수입니다. 그래서 그들은 정상적인 기능이지만 이름이 없습니다. 다음과 같은 형태입니다.
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!");
이 Lazy
클래스는 사용자가 요청할 때까지 계산되지 않는 값을 나타내도록 특별히 설계되었습니다. 구성 방법을 정의하는 메서드를 제공하여 구성하지만, 해당 메서드를 한 번만 실행하고 (값을 요청하는 여러 스레드가있는 경우에도) 추가 요청에 대해 이미 구성된 값을 반환합니다.
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
Lazy
처리 능력을 많이 요구하는 값에 사용되어야하며, (의 의미가 있기 때문에 당신이 상호 작용을 사용하지 않도록 .Value
이 속성이 아니라 (인터랙티브) 액션 유사한 값을 반환한다는 것입니다). 대신 이러한 작업에 대리자를 사용해야합니다.
Value
이 사용됩니다. DialogResult
메시지 상자를 표시 하여 받은 것입니다 . 이 솔루션과 델리게이트 사용의 주요 차이점은 값을 요청할 때마다 값을 다시 계산해야하는지 여부입니다. 요구 사항에 대한 나의 해석은 이것이 반복 되는 작업 이 아니라 개념적으로 값을 초기화 한다는 것입니다.
Lazy
쉽게 잘못 사용될 수 있습니다. 그것은 그 자체로 오버 헤드를 가지고 있으며, 작은 작업을 연기하기 위해 "단지"를 사용하면 얻는 것보다 더 많은 오버 헤드가 발생합니다. 속성에서 메시지 상자를 표시하는 것은 일반적으로 Lazy
. Btw, MSDN의 인용문 : "지연 초기화를 사용하여 대규모 또는 리소스 집약적 인 개체 생성을 연기" . 당신은 그것에 동의하지 않을 수 있지만 그것이 원래 설계된 것입니다.
Lazy
이와 같은 컨텍스트에서 성능 오버 헤드 는 확실히 무시할 수 있습니다. 사람이 메시지 상자를 클릭하기를 기다리는 시간에 비해 창백합니다. 대부분은 기본 애플리케이션의 실제 요구 사항에 달려 있습니다. 질문의 모호함은 객관적으로 정답을 불가능하게 만듭니다. 이것은 질문에 대한 하나의 해석입니다. 속성 getter에서 많은 작업을 수행하는 것은 나쁘다. 분명히 당신은의 전체 디자인에 근본적으로 반대합니다 Lazy
. 그 의견에 환영합니다.
MessageBox
오버 헤드는 무시할 만합니다 (속성 내부에서 UI를 사용하지 않을 것입니다). 나는 일반적으로 (deferring과 같은 2 + 3 * 4 / i
) 작은 작업을 의미 했는데, 여기서 클로저를 만드는 오버 헤드가 계산 자체보다 큽니다. 그리고 저는를 완전히 수용한다고 생각합니다 Lazy
. 사실 우리는 F #에서 많이 사용하고 (C #에서는 조금 덜 사용합니다), 특히 조심해야하는 어려운 방법을 배웠습니다. 성능 측면에서.
내가 귀하의 질문을 읽는 방식은 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);
... 당신이 요청한 것처럼, 변수로 할당 된 함수 (또는 여기서 "Action"은 void를 반환하기 때문에).
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