是否可以创建变量,并为其分配一行代码,例如:
ButtonClicked = (MessageBox.Show("Hello, World!"));
...所以当我使用变量时,它将执行代码行。
是否可以创建变量,并为其分配一行代码,例如:
ButtonClicked = (MessageBox.Show("Hello, World!"));
...所以当我使用变量时,它将执行代码行。
Answers:
您可以将其分配给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的参数列表(在本例中为none)。
例如,如果您想指定要显示的消息,则可以添加“ 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);
我们基本上创建了一个名为ButtonClicked的新变量,该变量具有ButtonClick类型(它是一个委托),并且在使用时将在OnButtonClick()方法中执行该方法。
要使用它,我们只需调用:ButtonClicked();
因此整个代码将是:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
从这里开始,我们可以转到lambda表达式,看看它们在您的情况下如何有用:
.NET库已经定义了许多委托,其中有些像Action这样,它们不接受任何参数且不返回任何值。它的定义是,public delegate void Action();
您可以始终根据需要使用它,而不必每次都定义一个新的委托。例如,在前面的上下文中,您可能已经编写了
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
会做同样的事情。
现在您已经看到了如何使用委托的不同方法,让我们使用我们的第一个lambda表达式。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!"))();
对不起,很长的帖子,希望它不会太混乱:)
编辑:我忘了提到一种替代形式,尽管它不经常使用,但它可以使lambda表达式更容易理解:
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!");
反过来,您可以使用lambda表达式,但是不需要(但在某些情况下可能)不需要定义参数的类型,例如,上面的代码可以简单地写为:
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
容易被错误使用。它本身具有开销,使用它“只是”延迟一个小任务将引起更多的开销。无论如何,从属性显示消息框都是(imo)不良做法Lazy
。顺便说一句,来自MSDN的我引用:“使用延迟初始化来延迟大型或资源密集型对象的创建”。您可以不同意这一点,但这就是最初设计的目的。
Lazy
在这种情况下的性能开销当然可以忽略不计;与等待人类点击消息框所花费的时间相比,它会显得苍白。它主要取决于底层应用程序的实际需求。问题的模糊性使得不可能客观上正确地回答。这是对该问题的一种解释。至于在吸气剂中做很多工作是不好的;显然,您从根本上反对的整个设计Lazy
。对此表示欢迎。
MessageBox
开销可以忽略不计(我只是不会在属性内使用UI)。我的意思是一般的小任务(例如deferring 2 + 3 * 4 / i
),其中创建闭包的开销大于计算本身。而且我想我完全拥护Lazy
,实际上我们在F#中使用了很多(在C#中很少使用),并且我们已经学会了必须谨慎使用的困难方法,尤其是。在性能方面。
我阅读您的问题的方式是在GUI控件的上下文中进行的?
如果在WPF中,请查看处理来自控件的命令的“正确”方法:http : //msdn.microsoft.com/zh-cn/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