.NET中开放与封闭委托有何区别?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2111个文字,预计阅读时间需要9分钟。
前言:这是这个人委托的系列理解系列的第二篇,部分翻译自Open Delegates vs. Closed Delegates – SLaks.Blog,好像还没有人翻译过,加上部分个人理解。希望对大家理解委托有所帮助。希望对大家理解委托有所帮助。
正文:.Net支持两种委托(Delegate),它们分别是开放委托(Open Delegate)和封闭委托(Closed Delegate)。下面简要介绍这两种委托的区别和用法。
1. 开放委托(Open Delegate)
开放委托允许在运行时动态地添加方法到委托中。这意味着可以在程序运行过程中向委托中添加任意数量的方法。
csharppublic delegate void MyDelegate();public class Program{ public static void Main() { MyDelegate myDelegate=new MyDelegate(DoSomething); myDelegate +=DoSomethingElse; myDelegate(); }
public static void DoSomething() { Console.WriteLine(DoSomething); }
public static void DoSomethingElse() { Console.WriteLine(DoSomethingElse); }}
2. 封闭委托(Closed Delegate)
封闭委托在编译时就已经确定了要执行的方法。这意味着无法在运行时向封闭委托中添加方法。
csharppublic delegate void MyDelegate();public class Program{ public static void Main() { MyDelegate myDelegate=new MyDelegate(DoSomething); myDelegate(); }
public static void DoSomething() { Console.WriteLine(DoSomething); }}
总结:
- 开放委托允许在运行时动态地添加方法,而封闭委托在编译时就已经确定了要执行的方法。- 开放委托更灵活,但可能会导致性能问题;封闭委托性能更好,但灵活性较低。
希望这篇文章能帮助大家更好地理解委托。
前言这是个人对委托的理解系列第二篇,部分翻译自 Open Delegates vs. Closed Delegates – SLaks.Blog,好像还没人翻译过,加上部分个人理解。希望能对大家理解委托有所帮助。
正文.Net支持两种委托:开放委托和封闭委托。open delegates和 closed delegates
封闭委托:译者注:这里不是作者这么分的,确实写在dotnet的官方文档和注释里。当然翻译的名称值得考量。
当你创建一个指向实例对象方法的委托时,这个实例对象就被保存在委托的Target属性中,这个属性(也就是包含方法的实例对象)被当作方法的第一个参数传给委托指向的方法。对于实例对象的方法来说,就是this,对于静态方法来说,就是方法的第一个参数。这样的委托被称为封闭委托(closed delegates)因为他们以js闭包的方式把静态方法的第一个参数或者实例方法的this封进了委托实例之中。
开放委托译者注: 这里说的很抽象,意思就是封闭委托会把某些参数作为
Target属性带进委托中。后面有例子说明。
我们同样也能创建一个不隐含传第一个参数的开式委托,这种委托不使用Target属性,相反,所有委托目标方法的参数都是按委托的形参列表实际传递的,包括第一个参数。因此,一个指向给定方法的开放委托一定比指向同一个方法的封闭委托多传一个参数(也就是this或者第一个参数)。开放委托一般用于指向静态方法(同理:封闭委托一般用于实例方法)。当你创建一个指向静态方法的委托时,你一般不想这个委托持有这个方法的第一个参数。
简短说明译者注:原文比较抽象,结合后面的例子比较容易理解。
除了上面说的这两种通用的情况来说(也就是静态方法创建开放委托,实例方法创建封闭委托),在.Net 2.0和之后我们还能创建指向实例方法的开放委托和指向静态方法的封闭委托。但是这样C#就没有相应的语法糖支持,只能通过Delegate.CreateDelegate方法来创建。
一般情况的例子 一般情况的封闭委托(实例方法)区分这两种委托主要看
Target属性,原文的例子不太有些不太容易理解。这里结合自己的理解。重新写了例子,读完本文的例子可以再去看原文的例子就比较容易理解了。
internal class HelloWorld
{
public void HelloWorldInstance() => Console.WriteLine("hello world");
public delegate void SayHi();
public void Main()
{
var helloWorldInstance = new SayHi(HelloWorldInstance);
}
}
这里实际调用的System.Private.CoreLib中的Delegate.CoreCLR.cs代码为:
[System.Diagnostics.DebuggerNonUserCode]
private void CtorClosed(object target, IntPtr methodPtr)
{
if (target == null)
ThrowNullThisInDelegateToInstance();
this._target = target;
this._methodPtr = methodPtr;
}
看名字就很容易理解,注意这里对Target的赋值且一定不为null。
internal class HelloWorld
{
public static void HelloWorldStatic(string msg) => Console.WriteLine(msg);
public delegate void SayHiWithParam(string msg);
public void Main()
{
var helloWorld3 = new SayHiWithParam(HelloWorldStatic);
helloWorld3("hello world");
}
}
这里实际调用的System.Private.CoreLib中的MulticastDelegate.cs代码为:
[System.Diagnostics.DebuggerNonUserCode]
private void CtorOpened(object target, IntPtr methodPtr, IntPtr shuffleThunk)
{
this._target = this;
this._methodPtr = shuffleThunk;
this._methodPtrAux = methodPtr;
}
注意:
- 这里的
target实际为null,所以_target的赋值对象是this,而创建出的委托的Target属性为null。 - 这里
_methodPtr的赋值对象是shuffleThunk。
前面说了,不一般情况下我们需要使用通过Delegate.CreateDelegate方法来创建委托。
internal class HelloWorld
{
public static void HelloWorldStatic(string msg) => Console.WriteLine(msg);
public void Main()
{
var closed = Delegate.CreateDelegate(typeof(Action), "a", typeof(HelloWorld).GetMethod(nameof(HelloWorld.HelloWorldStatic)));
closed.DynamicInvoke();
}
}
这里实际调用的System.Private.CoreLib中的Delegate.cs代码为:
// V2 api: Creates open or closed delegates to static or instance methods - relaxed signature checking allowed.
public static Delegate CreateDelegate(Type type, object? firstArgument, MethodInfo method) => CreateDelegate(type, firstArgument, method, throwOnBindFailure: true)!;
特别需要注意:
- 这里创建的委托类型为:
typeof(Action)不是typeof(Action<string>)因为,"a"做为第一个参数已经是委托的Target属性了。
public class HelloWorld
{
public void HelloWorldInstance() => Console.WriteLine("hello world");
public void Main()
{
var open = Delegate.CreateDelegate(typeof(Action<HelloWorld>), typeof(HelloWorld).GetMethod(nameof(HelloWorld.HelloWorldInstance)));
open.DynamicInvoke(this);
}
}
同样特别需要注意:
- 这里创建的委托类型为:
typeof(Action<HelloWorld>)不是typeof(Action) - 可以注意到委托的
Target属性为null。
原文中的其他注意点原文的例子较难一点,感兴趣的可以通过前文链接查看。接着我们回到原文。
原文中提供了其他部分需要注意的部分包括
- 不能使用值类型作为第一个参数创建静态方法的封闭委托。参考链接c# - Extension methods defined on value types cannot be used to create delegates - Why not? - Stack Overflow
- C# 3对创建封闭委托提供了部分语法支持,你可以从扩展方法创建委托,就好像它是它所扩展的类型的实例方法一样 例如:
var allNumbers = Enumerable.Range(1, Int32.MaxValue);
Func<int, IEnumerable<int>> countTo = allNumbers.Take;
countTo这里可以作为IEnumerable<int>的实例方法来使用。
- 作者最后说,除了扩展方法,特殊情况的委托的应用只占很小一部分,但对我们对委托的理解很重要。
me:不明觉厉。以及以上是这个系列的第二篇,有机会希望带大家更深入的理解委托。
本文共计2111个文字,预计阅读时间需要9分钟。
前言:这是这个人委托的系列理解系列的第二篇,部分翻译自Open Delegates vs. Closed Delegates – SLaks.Blog,好像还没有人翻译过,加上部分个人理解。希望对大家理解委托有所帮助。希望对大家理解委托有所帮助。
正文:.Net支持两种委托(Delegate),它们分别是开放委托(Open Delegate)和封闭委托(Closed Delegate)。下面简要介绍这两种委托的区别和用法。
1. 开放委托(Open Delegate)
开放委托允许在运行时动态地添加方法到委托中。这意味着可以在程序运行过程中向委托中添加任意数量的方法。
csharppublic delegate void MyDelegate();public class Program{ public static void Main() { MyDelegate myDelegate=new MyDelegate(DoSomething); myDelegate +=DoSomethingElse; myDelegate(); }
public static void DoSomething() { Console.WriteLine(DoSomething); }
public static void DoSomethingElse() { Console.WriteLine(DoSomethingElse); }}
2. 封闭委托(Closed Delegate)
封闭委托在编译时就已经确定了要执行的方法。这意味着无法在运行时向封闭委托中添加方法。
csharppublic delegate void MyDelegate();public class Program{ public static void Main() { MyDelegate myDelegate=new MyDelegate(DoSomething); myDelegate(); }
public static void DoSomething() { Console.WriteLine(DoSomething); }}
总结:
- 开放委托允许在运行时动态地添加方法,而封闭委托在编译时就已经确定了要执行的方法。- 开放委托更灵活,但可能会导致性能问题;封闭委托性能更好,但灵活性较低。
希望这篇文章能帮助大家更好地理解委托。
前言这是个人对委托的理解系列第二篇,部分翻译自 Open Delegates vs. Closed Delegates – SLaks.Blog,好像还没人翻译过,加上部分个人理解。希望能对大家理解委托有所帮助。
正文.Net支持两种委托:开放委托和封闭委托。open delegates和 closed delegates
封闭委托:译者注:这里不是作者这么分的,确实写在dotnet的官方文档和注释里。当然翻译的名称值得考量。
当你创建一个指向实例对象方法的委托时,这个实例对象就被保存在委托的Target属性中,这个属性(也就是包含方法的实例对象)被当作方法的第一个参数传给委托指向的方法。对于实例对象的方法来说,就是this,对于静态方法来说,就是方法的第一个参数。这样的委托被称为封闭委托(closed delegates)因为他们以js闭包的方式把静态方法的第一个参数或者实例方法的this封进了委托实例之中。
开放委托译者注: 这里说的很抽象,意思就是封闭委托会把某些参数作为
Target属性带进委托中。后面有例子说明。
我们同样也能创建一个不隐含传第一个参数的开式委托,这种委托不使用Target属性,相反,所有委托目标方法的参数都是按委托的形参列表实际传递的,包括第一个参数。因此,一个指向给定方法的开放委托一定比指向同一个方法的封闭委托多传一个参数(也就是this或者第一个参数)。开放委托一般用于指向静态方法(同理:封闭委托一般用于实例方法)。当你创建一个指向静态方法的委托时,你一般不想这个委托持有这个方法的第一个参数。
简短说明译者注:原文比较抽象,结合后面的例子比较容易理解。
除了上面说的这两种通用的情况来说(也就是静态方法创建开放委托,实例方法创建封闭委托),在.Net 2.0和之后我们还能创建指向实例方法的开放委托和指向静态方法的封闭委托。但是这样C#就没有相应的语法糖支持,只能通过Delegate.CreateDelegate方法来创建。
一般情况的例子 一般情况的封闭委托(实例方法)区分这两种委托主要看
Target属性,原文的例子不太有些不太容易理解。这里结合自己的理解。重新写了例子,读完本文的例子可以再去看原文的例子就比较容易理解了。
internal class HelloWorld
{
public void HelloWorldInstance() => Console.WriteLine("hello world");
public delegate void SayHi();
public void Main()
{
var helloWorldInstance = new SayHi(HelloWorldInstance);
}
}
这里实际调用的System.Private.CoreLib中的Delegate.CoreCLR.cs代码为:
[System.Diagnostics.DebuggerNonUserCode]
private void CtorClosed(object target, IntPtr methodPtr)
{
if (target == null)
ThrowNullThisInDelegateToInstance();
this._target = target;
this._methodPtr = methodPtr;
}
看名字就很容易理解,注意这里对Target的赋值且一定不为null。
internal class HelloWorld
{
public static void HelloWorldStatic(string msg) => Console.WriteLine(msg);
public delegate void SayHiWithParam(string msg);
public void Main()
{
var helloWorld3 = new SayHiWithParam(HelloWorldStatic);
helloWorld3("hello world");
}
}
这里实际调用的System.Private.CoreLib中的MulticastDelegate.cs代码为:
[System.Diagnostics.DebuggerNonUserCode]
private void CtorOpened(object target, IntPtr methodPtr, IntPtr shuffleThunk)
{
this._target = this;
this._methodPtr = shuffleThunk;
this._methodPtrAux = methodPtr;
}
注意:
- 这里的
target实际为null,所以_target的赋值对象是this,而创建出的委托的Target属性为null。 - 这里
_methodPtr的赋值对象是shuffleThunk。
前面说了,不一般情况下我们需要使用通过Delegate.CreateDelegate方法来创建委托。
internal class HelloWorld
{
public static void HelloWorldStatic(string msg) => Console.WriteLine(msg);
public void Main()
{
var closed = Delegate.CreateDelegate(typeof(Action), "a", typeof(HelloWorld).GetMethod(nameof(HelloWorld.HelloWorldStatic)));
closed.DynamicInvoke();
}
}
这里实际调用的System.Private.CoreLib中的Delegate.cs代码为:
// V2 api: Creates open or closed delegates to static or instance methods - relaxed signature checking allowed.
public static Delegate CreateDelegate(Type type, object? firstArgument, MethodInfo method) => CreateDelegate(type, firstArgument, method, throwOnBindFailure: true)!;
特别需要注意:
- 这里创建的委托类型为:
typeof(Action)不是typeof(Action<string>)因为,"a"做为第一个参数已经是委托的Target属性了。
public class HelloWorld
{
public void HelloWorldInstance() => Console.WriteLine("hello world");
public void Main()
{
var open = Delegate.CreateDelegate(typeof(Action<HelloWorld>), typeof(HelloWorld).GetMethod(nameof(HelloWorld.HelloWorldInstance)));
open.DynamicInvoke(this);
}
}
同样特别需要注意:
- 这里创建的委托类型为:
typeof(Action<HelloWorld>)不是typeof(Action) - 可以注意到委托的
Target属性为null。
原文中的其他注意点原文的例子较难一点,感兴趣的可以通过前文链接查看。接着我们回到原文。
原文中提供了其他部分需要注意的部分包括
- 不能使用值类型作为第一个参数创建静态方法的封闭委托。参考链接c# - Extension methods defined on value types cannot be used to create delegates - Why not? - Stack Overflow
- C# 3对创建封闭委托提供了部分语法支持,你可以从扩展方法创建委托,就好像它是它所扩展的类型的实例方法一样 例如:
var allNumbers = Enumerable.Range(1, Int32.MaxValue);
Func<int, IEnumerable<int>> countTo = allNumbers.Take;
countTo这里可以作为IEnumerable<int>的实例方法来使用。
- 作者最后说,除了扩展方法,特殊情况的委托的应用只占很小一部分,但对我们对委托的理解很重要。
me:不明觉厉。以及以上是这个系列的第二篇,有机会希望带大家更深入的理解委托。

