代码之家  ›  专栏  ›  技术社区  ›  Maxime Rouiller

什么时候在C#中使用委托?[闭门]

  •  100
  • Maxime Rouiller  · 技术社区  · 16 年前

    在C#中,您对委托的用法是什么?

    20 回复  |  直到 15 年前
        1
  •  100
  •   Jon Skeet    16 年前

    现在我们在C#中有了lambda表达式和匿名方法,我使用的委托就更多了。在C#1中,总是需要一个单独的方法来实现逻辑,使用委托通常没有意义。这些天来,我使用代理来:

    • 事件处理程序(用于GUI等)
    • 回调(例如,对于异步API)
        2
  •  29
  •   Andrew Hare    15 年前

    代表在许多方面都非常有用。

    其中一个目的是使用它们过滤数据序列。在本例中,您将使用谓词委托,它接受一个参数并根据委托本身的实现返回true或false。

    下面是一个愚蠢的例子——我相信你可以从中推断出更有用的东西:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    
    class Program
    {
        static void Main()
        {
            List<String> names = new List<String>
            {
                "Nicole Hare",
                "Michael Hare",
                "Joe Hare",
                "Sammy Hare",
                "George Washington",
            };
    
            // Here I am passing "inMyFamily" to the "Where" extension method
            // on my List<String>.  The C# compiler automatically creates 
            // a delegate instance for me.
            IEnumerable<String> myFamily = names.Where(inMyFamily);
    
            foreach (String name in myFamily)
                Console.WriteLine(name);
        }
    
        static Boolean inMyFamily(String name)
        {
            return name.EndsWith("Hare");
        }
    }
    
        3
  •  15
  •   Maxime Rouiller    16 年前

    一位同事刚刚问了我一个问题-代理在.NET中的作用是什么?我的回答非常简短,他在网上没有找到:延迟方法的执行。

    LosTechies

    就像林克做的那样。

        4
  •  12
  •   harpo Binary Worrier    16 年前

    实例

    考虑“资源借用”模式。您希望控制资源的创建和清理,同时允许客户端代码“借用”中间的资源。

    这声明了一个委托类型。

    public delegate void DataReaderUser( System.Data.IDataReader dataReader );
    

    任何与此签名匹配的方法都可以用于实例化此类型的委托。在C#2.0中,这可以隐式地完成,只需使用方法名,也可以使用匿名方法。

    此方法使用类型作为参数。注意委托的调用。

    public class DataProvider
    {
        protected string _connectionString;
    
        public DataProvider( string psConnectionString )
        {
            _connectionString = psConnectionString;
        }
    
        public void UseReader( string psSELECT, DataReaderUser readerUser )
        {
            using ( SqlConnection connection = new SqlConnection( _connectionString ) )
            try
            {
                SqlCommand command = new SqlCommand( psSELECT, connection );
                connection.Open();
                SqlDataReader reader = command.ExecuteReader();
    
                while ( reader.Read() )
                    readerUser( reader );  // the delegate is invoked
            }
            catch ( System.Exception ex )
            {
                // handle exception
                throw ex;
            }
        }
    }
    

    string sTableName = "test";
    string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";
    
    DataProvider.UseReader( sQuery,
        delegate( System.Data.IDataReader reader )
        {
            Console.WriteLine( sTableName + "." + reader[0] );
        } );
    
        5
  •  11
  •   jonnii    15 年前

    委托通常可以用一种方法代替接口,一个常见的例子就是观察者模式。在其他语言中,如果您希望收到某件事情发生的通知,您可以定义如下内容:

    class IObserver{ void Notify(...); }
    

    myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
    

    myList.Where(i => i > 10);
    

    上面是lambda语法的一个示例,也可以编写如下:

    myList.Where(delegate(int i){ return i > 10; });
    

    使用委托的另一个有用的地方是注册工厂函数,例如:

    myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
    var widget = myFactory.BuildWidget(Widgets.Foo);
    

        6
  •  10
  •   will    12 年前

    我来得真的很晚,但我很难弄清楚今天代表们的目的,我写了两个简单的程序,它们给出了相同的输出,我认为这很好地解释了它们的目的。

    NoDelegates.cs

    using System;
    
    public class Test {
        public const int MAX_VALUE = 255;
        public const int MIN_VALUE = 10;
    
        public static void checkInt(int a) {
            Console.Write("checkInt result of {0}: ", a);
            if (a < MAX_VALUE && a > MIN_VALUE)
                Console.WriteLine("max and min value is valid");
            else
                Console.WriteLine("max and min value is not valid");
        }
    
        public static void checkMax(int a) {
            Console.Write("checkMax result of {0}: ", a);
            if (a < MAX_VALUE)
                Console.WriteLine("max value is valid");
            else
                Console.WriteLine("max value is not valid");
        }
    
        public static void checkMin(int a) {
            Console.Write("checkMin result of {0}: ", a);
            if (a > MIN_VALUE)
                Console.WriteLine("min value is valid");
            else
                Console.WriteLine("min value is not valid");
            Console.WriteLine("");
        }
    }
    
    public class Driver {
        public static void Main(string [] args) {
            Test.checkInt(1);
            Test.checkMax(1);
            Test.checkMin(1);
    
            Test.checkInt(10);
            Test.checkMax(10);
            Test.checkMin(10);
    
            Test.checkInt(20);
            Test.checkMax(20);
            Test.checkMin(20);
    
            Test.checkInt(30);
            Test.checkMax(30);
            Test.checkMin(30);
    
            Test.checkInt(254);
            Test.checkMax(254);
            Test.checkMin(254);
    
            Test.checkInt(255);
            Test.checkMax(255);
            Test.checkMin(255);
    
            Test.checkInt(256);
            Test.checkMax(256);
            Test.checkMin(256);
        }
    }
    

    using System;
    
    public delegate void Valid(int a);
    
    public class Test {
        public const int MAX_VALUE = 255;
        public const int MIN_VALUE = 10;
    
        public static void checkInt(int a) {
            Console.Write("checkInt result of {0}: ", a);
            if (a < MAX_VALUE && a > MIN_VALUE)
                Console.WriteLine("max and min value is valid");
            else
                Console.WriteLine("max and min value is not valid");
        }
    
        public static void checkMax(int a) {
            Console.Write("checkMax result of {0}: ", a);
            if (a < MAX_VALUE)
                Console.WriteLine("max value is valid");
            else
                Console.WriteLine("max value is not valid");
        }
    
        public static void checkMin(int a) {
            Console.Write("checkMin result of {0}: ", a);
            if (a > MIN_VALUE)
                Console.WriteLine("min value is valid");
            else
                Console.WriteLine("min value is not valid");
            Console.WriteLine("");
        }
    }
    
    public class Driver {
        public static void Main(string [] args) {
            Valid v1 = new Valid(Test.checkInt);
            v1 += new Valid(Test.checkMax);
            v1 += new Valid(Test.checkMin);
            v1(1);
            v1(10);
            v1(20);
            v1(30);
            v1(254);
            v1(255);
            v1(256);
        }
    }
    
        7
  •  5
  •   Marc Gravell    16 年前

    一个稍微不同的用途是加速反射;i、 代替每次使用反射,你可以使用 Delegate.CreateDelegate 创建方法(a)的(类型化)委托 MethodInfo ),并调用该代理。这就是 每次通话更快,因为检查已经完成。

    具有 Expression ,您也可以执行相同的操作来动态创建代码-例如,您可以轻松创建 表示在运行时选择的类型的+运算符(为泛型提供运算符支持,而该语言不提供);你可以编译一个 表示

        8
  •  5
  •   Reed Copsey    15 年前

    代理在您使用事件的任何时候都会被使用,这是代理工作的机制。

    此外,委托对于诸如使用LINQ查询之类的事情非常有用。例如,许多LINQ查询接受委托(通常是 Func<T,TResult> )它可以用于过滤。

        9
  •  4
  •   Manu JCasso    16 年前

        10
  •  2
  •   Konrad Viltersten    12 年前

    我们可以看到一个例子 here

        11
  •  1
  •   Danny Frencham    16 年前

    我使用代理与线程通信。

    例如,我可能有一个下载文件的win forms应用程序。应用程序启动一个工作线程进行下载(这会阻止GUI锁定)。工作线程使用代理将状态消息(如下载进度)发送回主程序,以便GUI可以更新状态栏。

        12
  •  0
  •   Patrick Desjardins    16 年前
    1. 对于事件处理程序

    2. 在方法参数中传递方法的步骤

        13
  •  0
  •   x0n    16 年前

    第一行用法是替换观察者/可观察(事件)模式。第二,战略模式的优雅版本。可以收集各种其他用法,尽管我认为比前两种更为深奥。

        14
  •  0
  •   Jeffe Jeffe    16 年前

    事件、其他anynch操作

        15
  •  0
  •   Bob King    16 年前

    任何时候都可以封装行为,但要以统一的方式调用它。事件处理程序、回调函数等。您可以使用接口和强制转换完成类似的事情,但有时,行为不一定与 类型 对象

        16
  •  0
  •   Santiago Palladino    16 年前

    惰性参数初始化!除了前面的所有答案(策略模式、观察者模式等),委托还允许您处理参数的延迟初始化。例如,假设您有一个函数Download(),它需要花费大量时间并返回某个DownloadedObject。此对象由存储器根据特定条件使用。通常,您会:

    storage.Store(conditions, Download(item))
    

    但是,对于委托(更准确地说,lambdas),您可以通过更改store的签名来执行以下操作,以便它接收条件和Func<项目,下载对象>然后像这样使用它:

    storage.Store(conditions, (item) => Download(item))
    

    因此,存储将仅在必要时评估委托,并根据条件执行下载。

        17
  •  0
  •   Rajeshwaran S P    16 年前

    1. 事件处理
    2. 多铸件
        18
  •  0
  •   GregUzelac    16 年前

    数组.Sort(T[]数组,比较),List.Sort(比较)等中的比较参数

        19
  •  0
  •   Puppy    14 年前

    据我所知,委托可以转换为函数指针。这使得在与采用函数指针的本机代码进行互操作时变得更加容易,因为它们可以有效地面向对象,即使最初的程序员没有为此做任何准备。

        20
  •  0
  •   JSK NS harvey    12 年前

    委托用于通过引用调用方法。 例如:

      delegate void del_(int no1,int no2);
    class Math
    {
       public static void add(int x,int y)
       {
         Console.WriteLine(x+y);
       }
       public static void sub(int x,int y)
       {
         Console.WriteLine(x-y);
       }
    }
    
    
    
        class Program
        {
            static void Main(string[] args)
            {
                del_ d1 = new del_(Math.add);
                d1(10, 20);
                del_ d2 = new del_(Math.sub);
                d2(20, 10);
                Console.ReadKey();
            }
        }