【发布时间】:2010-12-07 02:14:35
【问题描述】:
我之前问过一个关于 Delegates 的问题,是否有人有必须使用委托的场景?这对我的 C# 代码有何改进?
正如我在许多场景中使用它一样,我似乎总是能够围绕它进行编程。
【问题讨论】:
-
事件由代表实现。你不使用事件吗?
我之前问过一个关于 Delegates 的问题,是否有人有必须使用委托的场景?这对我的 C# 代码有何改进?
正如我在许多场景中使用它一样,我似乎总是能够围绕它进行编程。
【问题讨论】:
无论何时使用Strategy Pattern 或观察者模式,委托都比使用接口更容易。
【讨论】:
没有人提到这一点,但是如果您将 LINQ 与 Lambda 一起使用,您将一直使用匿名方法。从技术上讲,它们仍然是代表。
假设您有一个名为 Person 的类
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
你想实现一个 find 方法,你可以根据他们的名字找到这个人
public Person Where(List<Person> list, string firstName)
{
//find the string
foreach(Person item in list)
if(item.FirstName.Equals(firstName))
return item;
}
这是一个非常具体的搜索,不是很动态,这意味着如果您想按姓氏搜索,您必须更改此方法或编写一个新方法。
幸运的是,LINQ 提供了一个名为 Where 的扩展方法,您需要将 delegate 传递给该方法,您可以在匿名方法的帮助下动态创建该方法。 p>
例如
string searchString = "Stan";
list.Where( person => person.FirstName.Equals(searchString));
但如果您想更改为按姓氏搜索,您只需这样做
string searchString = "R";
list.Where( person => person.LastName.Equals(searchString));
这个例子可能不是你想要的,但我只是想表明,有时我们一直在使用委托而没有考虑或意识到这一点。
【讨论】:
假设您不是在谈论事件 - 当然您可以围绕它进行编程。关键是让它更好和更干净。
protected void Sort()
{
foreach (string key in _dBase.Keys)
{
Array.Sort<Pair<string, Dictionary<string, T>>>(_dBase[key],
new Comparison<Pair<string, Dictionary<string, T>>>(
delegate(Pair<string, Dictionary<string, T>> a, Pair<string, Dictionary<string, T>> b)
{
if (a == null && b != null)
return 1;
else if (a != null && b == null)
return -1;
else if (a == null && b == null)
return 0;
else
return a.First.CompareTo(b.First);
}));
}
}
如果没有内联委托,我可以这样做吗?当然。我会在我的类中有一个仅用于这个实例的软盘私有方法吗?是的。
编辑:如 cmets 中所述,您可以简化:
Array.Sort<Pair<string, Dictionary<string, T>>>(_dBase[key],
new Comparison<Pair<string, Dictionary<string, T>>>(
delegate(Pair<string, Dictionary<string, T>> a, Pair<string, Dictionary<string, T>> b)
{
到
Array.Sort<Pair<string, Dictionary<string, T>>>(_dBase[key], (a,b) =>
{
【讨论】:
如果您想象 C# 没有委托,您通常会遇到这样的情况,即您拥有具有一种方法的类或接口。该方法的名称是多余的。例如
public interface IGetMail
{
Mail JustGetTheMail();
}
界面就是关于那个方法的。对该类型对象的引用实际上只不过是对单个可调用方法的引用。调用代码:
Mail m = getMail.JustGetTheMail();
可以简写为:
Mail m = getMail();
编译器可以毫无歧义地将其作为“语法糖”来执行,因为只有一种方法可以调用 getMail 引用。
所以让我们将该功能添加到我们的 C# 编译器中。现在,在声明这些类型时,我们也可以让它更整洁一些。调用的时候不需要指定方法名,为什么要给方法起个名字呢?
让我们选择一个标准方法名称,Invoke,即
public interface IGetMail
{
Mail Invoke();
}
我们将添加更多语法糖,以便我们将其写为:
public delegate Mail GetMail();
嘿,转眼间。我们在 C# 编译器中添加了委托。
(从技术上讲,CLR 也知道委托,因此 C# 编译器不会生成一个接口,而是生成一个特殊的“委托”类型,它支持异步调用,并操作一个不可变的委托列表并将它们视为一个单一的引用;但在基本形式中,它可以用接口完成。有一个建议为 Java 这样做)。
然后我们可以更进一步并添加匿名委托 - 使它们以接口所没有的方式简洁地实现。
所以回答你的问题 - 只要你的界面有一个方法,它就可以是一个委托,你将能够大大减少你必须编写的垃圾代码的数量。
【讨论】:
现实世界的用法:
3.现在,在一个新的 Win Form 中,当您拖入 Checker...并且您的目标是确保单击 chkA 时,您必须更改标签的背景颜色...lblColorPicker。
请注意,lblColorPicker 是一个存在于表单中的控件,并不直接绑定到 Checker。
您将如何实现这一目标?
答案:
通过这种方式,您可以控制 chkA...通过任何新形式的新事件,通过引用事件...通过您刚刚编写的委托。
所以,对于现实世界的使用来说非常重要!
如果不编写委托,这个目标无法实现。
如果您不这么认为......或者如果您需要更多详细说明,请告诉我。
【讨论】:
匿名委托在某些情况下使代码更具可读性(您不必转到另一个方法来查看属于您的方法的代码:
Winform 示例
class MyForm:Form{
//...
protected override void OnLoad(EventArg e){
this.Cursor=Cursors.Wait();
this.Enabled=false;
// do a long running DB operation without blocking the UI Thread
ThreadPool.QueueUserWorkItem(state=>{
DoLongDBOperation();
// re enable the form
BeginInvoke(new Action(()=>{ this.Cursor=Cursors.Default;this.Enabled=true;}));
});
}
【讨论】:
如果您将事件添加到您的班级或正在做任何异步的事情(还有其他几个很好的理由拥有委托),那么委托是绝对必须的。好处是它是一种非常灵活的方法。
【讨论】:
我认为您指的是定义自定义委托?
EventHandler 已将自定义委托定义的需求降到最低,但如果您想向方法签名添加其他参数,它们仍然很有用。
【讨论】:
当您需要修改或更改 winForms 控件的任何属性时,您需要使用委托将控制权传递回创建该控件的线程……这里仅举一个例子。
【讨论】:
一个示例是发布/订阅消息调度程序。您需要向调度程序注册事件,然后适当地调用它们。这使您可以很容易地连接不同的代码片段。我想不出不使用委托的方法
【讨论】:
假设您有一个响应不同按键的控制台应用程序:
Action a = () => {/* Do Stuff*/};
Action b = () => {/* Do Stuff*/};
Action c = () => {/* Do Stuff*/};
Action d = () => {/* Do Stuff*/};
Action e = () => {/* Do Stuff*/};
Action f = () => {/* Do Stuff*/};
Action g = () => {/* Do Stuff*/};
Action h = () => {/* Do Stuff*/};
Action i = () => {/* Do Stuff*/};
Action j = () => {/* Do Stuff*/};
List<Action> actions = new List<Action>() {a,b,c,d,e,f,g,h,i,j};
string line;
while((line = Console.ReadKey().KeyChar) != 'q')
{
if(line.isBetween_0_and_9())
{
actions[line.ParseInt()]();
}
}
您显然可以只使用一堆 If,但这不仅更容易,而且几乎可以肯定更清晰/可读。
【讨论】: