C# 代表与事件
当一个类不能(或不应该)做某事时,事件或委托可能是一个解决方案 说 在这里,在代理方法中,科学家方法直接由总统课堂使用,如果一位总统提出一个问题,科学家会回答C# 代表与事件,c#,.net,vb.net,events,delegates,C#,.net,Vb.net,Events,Delegates,当一个类不能(或不应该)做某事时,事件或委托可能是一个解决方案 说 在这里,在代理方法中,科学家方法直接由总统课堂使用,如果一位总统提出一个问题,科学家会回答 然而,在.NETFramework代码中,我没有观察到委托的直接使用。直接使用它是错误的吗?如果,为什么?在框架中大量使用委托。LINQ就是一个明显的例子: var result = someCollection.Where(input => input.MatchesSomeCriteria); 其中接受具有特定签名的委托,该签
然而,在.NETFramework代码中,我没有观察到委托的直接使用。直接使用它是错误的吗?如果,为什么?在框架中大量使用委托。LINQ就是一个明显的例子:
var result = someCollection.Where(input => input.MatchesSomeCriteria);
其中
接受具有特定签名的委托,该签名被调用以确定是否在结果中包含项。最常用的方法是如上所示的lamba方法,但您也可以传递一个方法:
string[] nums = new[]{ "1", "2", "3"};
int sum = nums.Select(int.Parse).Sum();
int.Parse
与本例中Select
所需的委托签名(Func
)相匹配,因此将为nums
中的每个字符串调用该签名
通常,当委托被直接使用时,它们被作为将使用它们的方法调用的输入。尽管在某些地方它们是使用者状态的一部分(例如,有一些属于委托类型的属性),但它们并不多。在原始环境中处理委托可能需要一些 样板代码(定义委托、声明必要的成员变量和创建自定义 保留封装的注册/注销方法等) 除了输入时间之外,在raw中使用委托作为应用程序回调的另一个问题 机制是这样一个事实:如果不将类的委托成员变量定义为private,则 调用方将直接访问委托对象。如果是这种情况,调用方将能够 将变量重新分配给新的委托对象(有效地删除要执行的当前函数列表
调用)更糟糕的是,调用方可以直接调用代理的调用列表。事件 事件实际上是我非常喜欢.net的一个方面,因为它可以让你声明一个更干净的接口。您可以拥有一个总统类,该类宣布它需要一个答案,而无需将其绑定到应答代理的实现,如
interface IPresident
{
event Action<QuestionArgs, IPresident> HasQuestion;
void RecieveAnswer(QuestionArgs,Answer);
}
如果一个新的班级想要回答校长的问题,他们所需要做的就是倾听事件发出的信号,有一个问题需要回答,然后在他们能够回答的情况下回答。如果科学家想回答其他人的问题,我们只需要实现一种与他们的事件相关的方法
直接委托调用
上面概述的委托方法的问题是它破坏了封装。它将科学家和总裁的实现紧密结合在一起,使代码变得脆弱。当你有其他人回答问题时会发生什么?在您的示例中,您需要修改Scientist实现以添加新功能,这被称为“脆弱”代码,这是一件坏事。这种技巧在构图中确实有一定的作用,但它很少是最好的选择
linq情况不同,因为您没有将委托公开为类/接口的成员。相反,您使用它作为调用方声明的函子,让您知道调用方感兴趣的信息。因为您正在进行“往返”封装,所以封装保持不变。
这使您可以定义非常干净和强大的API
我们可以以科学家为例,利用这项技术对其进行扩展,让人们发现我们可以回答这样的问题
partial class Scientist
{
public IEnumerable<QuestionArgs> FindQuestions(Predicate<QuestionArgs> interest, IPresident asker)
{
return this.Questions.Where( x => interest(x) == true && x.IsAuthorizedToAsk(asker))
}
}
// ...
partial class President
{
FirePhysicists()
{
foreach(var scientist in scientists)
{
if(scientist.FindQuestions(x => x.Catagory == QuestionCatagory.Physics, this).Count != 0)
{
scientist.Fire();
}
}
}
}
部分类科学家
{
公共IEnumerable FindQuestions(谓词兴趣,IPresident询问者)
{
返回此.Questions.Where(x=>interest(x)=true&&x.IsAuthorizedToAsk(asker))
}
}
// ...
半班制校长
{
火物理学家()
{
foreach(科学家中的var科学家)
{
if(科学家.FindQuestions(x=>x.Catagory==QuestionCatagory.Physics,this).Count!=0)
{
科学家。火();
}
}
}
}
请注意,FindQuestions
方法如何让我们不必实现一堆其他代码来审问科学家,如果没有传递代理的能力,我们将需要这些代码。虽然这不是唯一一种直接调用委托的情况,但它是最常见的委托之一
直接使用它是错误的吗?如果,为什么
不,没有错
我是这样想的。委托字段与事件的关系就像字符串字段与属性的关系一样。也就是说,您可能有:
class Car
{
private string modelName;
public string ModelName { get { return this.modelName; } }
...
模型名称在逻辑上是汽车的一个属性。当有人问你开什么样的车,你说“一辆福特福克斯”,你是在描述这辆车的特性。你不认为“福特福克斯”是一个“领域”或“字符串”,你认为它是一种汽车的名称。在计算机程序中,字符串字段只是名称存储方式的实现细节。属性可以是字符串,也可以是枚举,或者其他任何内容;要点是,从逻辑上讲,汽车有型号名称,而不是字符串字段
事件和委托的方式相同。汽车可以有一个“爆炸”事件(也许你正在编写一个视频游戏!),爆炸事件由一个委托类型的字段实现。爆炸是汽车的逻辑行为;委托字段是实现事件的机制
那么,直接使用代理是否“错误”?不,当然不是。只不过直接使用字符串是“错误的”。有时需要操纵非属性的字符串,有时需要操纵非事件的委托
诀窍是编写清楚地将机械过程与机械过程分开的代码
partial class Scientist
{
public IEnumerable<QuestionArgs> FindQuestions(Predicate<QuestionArgs> interest, IPresident asker)
{
return this.Questions.Where( x => interest(x) == true && x.IsAuthorizedToAsk(asker))
}
}
// ...
partial class President
{
FirePhysicists()
{
foreach(var scientist in scientists)
{
if(scientist.FindQuestions(x => x.Catagory == QuestionCatagory.Physics, this).Count != 0)
{
scientist.Fire();
}
}
}
}
class Car
{
private string modelName;
public string ModelName { get { return this.modelName; } }
...