C#代表真实世界用法
我之前曾问过一个关于代表的问题,是否有人必须拥有必须拥有的情况,我必须使用委托? 这如何改善我的C#代码?
就像我使用它的许多场景一样,我似乎总是可以围绕它编程。
假设你不是在谈论事件 – 当然你可以围绕它进行编程。 关键是要让它更好 , 更清洁 。
protected void Sort() { foreach (string key in _dBase.Keys) { Array.Sort>>(_dBase[key], new Comparison>>( delegate(Pair> a, Pair> 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); })); } }
没有内联代表我可以这样做吗? 当然。 我的类中是否有一个只用于这个实例的软盘私有方法? 对。
编辑:如评论中所述,您可以简化:
Array.Sort>>(_dBase[key], new Comparison>>( delegate(Pair> a, Pair> b) {
至
Array.Sort>>(_dBase[key], (a,b) => {
每当您使用策略模式或观察者模式时,委托使您的工作比使用接口更容易。
如果您想象没有委托的C#,您通常会遇到使用一种方法拥有类或接口的情况。 该方法的名称是多余的。 例如
public interface IGetMail { Mail JustGetTheMail(); }
界面就是那个方法。 对该类型的对象的引用实际上只不过是对单个可调用方法的引用。 调用代码:
Mail m = getMail.JustGetTheMail();
可以简化为:
Mail m = getMail();
编译器可以将其作为“语法糖”而没有任何歧义,因为只有一种方法可以调用getMail
引用。
所以让我们将这个function添加到我们的C#编译器中。 现在,在声明这些类型时,我们也可以使它更整洁。 调用它时我们不需要指定方法名称,那么为什么我们必须首先给该方法命名?
让我们选择一个标准方法名称Invoke
,即
public interface IGetMail { Mail Invoke(); }
我们将添加更多的语法糖,以便我们将其写为:
public delegate Mail GetMail();
嘿presto。 我们已经将代理添加到我们的C#编译器中。
(从技术上讲,CLR也知道代理,因此C#编译器不是生成接口,而是生成一种特殊的“委托”类型,它支持异步调用,并操纵不可变的委托列表并将它们作为单个引用处理;但是在基本forms中,它可以通过接口完成。有人建议为Java做这件事。
然后我们可以进一步添加匿名委托 – 使它们简洁,以接口不是这样的方式实现。
所以要回答你的问题 – 任何时候你的界面有一个方法,它可能是一个委托,你将能够认真减少你必须编写的垃圾代码的数量。
没有人提到这一点,但如果你使用LINQ和Lambda,你总是使用匿名方法。 哪些技术上仍然是代表 。
假设你有一个名为Person的类
class Person { public string FirstName { get; set; } public string LastName { get; set; } }
并且您希望实现一种find方法,您可以根据其FirstName找到该人
public Person Where(List list, string firstName) { //find the string foreach(Person item in list) if(item.FirstName.Equals(firstName)) return item; }
这是一个非常具体的搜索,而不是非常动态,这意味着如果您想通过LastName进行搜索,则必须更改此方法或编写新方法。
幸运的是LINQ提供了一个名为Where的扩展方法,你需要传递一个委托 ,你可以借助匿名方法动态创建委托 。
例如
string searchString = "Stan"; list.Where( person => person.FirstName.Equals(searchString));
但如果您想更改为按LastName搜索,您只需执行此操作即可
string searchString = "R"; list.Where( person => person.LastName.Equals(searchString));
这个例子可能不是你想要的,但我只是想表明,有时我们一直使用代理而不考虑它或实现它。
真实世界用法:
- 假设您有一个名为Checker的简单用户控件 – 它只包含2个复选框 – chkA和chkB。
- 在用户控件中,您可以通过实现chkA和ChkB的相应事件来控制检查/取消选中事件
3.现在,在一个新的Win Form中,当你拖入Checker时 ……你的目标是确保在点击chkA时你必须改变标签的背景颜色…… lblColorPicker。
请注意,lblColorPicker是一个存在于表单中的控件,并不直接绑定到Checker 。
你将如何实现这一目标?
回答:
- 首先,您必须为用户控件Checker创建一个新事件。
- 要创建这个新事件,首先要在用户控件中创建一个委托,然后使用此委托作为您正在编写的新事件的定义类型。
- 然后,此事件必须映射到用户控件中的chkA …事件。
通过这种方式,您可以通过引用事件来控制chkA …来自任何新表单…通过您刚刚编写的委托。
所以,真实世界的使用!
在编写代表时无法实现此目标。
如果您不这么认为,请告诉我……或者您是否需要更多详细说明。
在某些情况下,匿名委托使代码更具可读性(您不必转到另一种方法来查看属于您的方法的代码:
Winforms示例
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;})); }); }
如果你向你的class级添加事件或做任何不正常的事情(代表们还有其他几个很好的理由),代表是绝对必须拥有的。 好处是它是一种非常灵活的方法。
我想你指的是定义自定义代理?
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 actions = new List () {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()](); } }
显然你可以使用一堆Ifs,但这不仅更容易,而且几乎可以肯定更清晰/可读。
- 迁移到.Net4后,C#错误“语言不支持”
- 为什么Control.FromHandle(IntPtr)在一个挂钩进程中返回null并返回“Form”的有效对象? 在另一个钩过程中?
- DataGridView锁定在inheritance的UserControl上
- System.Net.WebException:无法解析远程名称:
- 需要调试从客户端计算机请求的Web API服务 – 需要帮助,我该怎么做?
- ASP.NET Web API跨请求缓存操作筛选器属性
- 异步迭代器任务<IEnumerable >
- 查找.NET中的哪些编码是ASCII兼容的
- 生产中的Azure SDK 2.2:无法加载文件或程序集“msshrtmi”或其依赖项之一。 该系统找不到指定的文件