C #에서 델리게이트를 어떻게 사용합니까?
답변
이제 C #에 람다 식과 익명 메서드가 있으므로 대리자를 훨씬 더 많이 사용합니다. 논리를 구현하기 위해 항상 별도의 메서드가 있어야하는 C # 1에서는 대리자를 사용하는 것이 종종 의미가 없었습니다. 요즘에는 다음을 위해 대리자를 사용합니다.
- 이벤트 핸들러 (GUI 등)
- 시작 스레드
- 콜백 (예 : 비동기 API)
- LINQ 및 유사 (List.Find 등)
- 내부에 특수 논리가 포함 된 “템플릿”코드를 효과적으로 적용하려는 다른 곳 (대리자가 전문화를 제공하는 곳)
답변
대리인은 여러 목적에 매우 유용합니다.
이러한 목적 중 하나는 데이터 시퀀스를 필터링하는 데 사용하는 것입니다. 이 경우 하나의 인수를 받아들이고 대리자 자체의 구현에 따라 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");
}
}
답변
또 다른 흥미로운 답변을 찾았습니다.
동료가 방금이 질문을했습니다. .NET에서 대리인의 요점은 무엇입니까? 내 대답은 매우 짧았고 그가 온라인에서 찾지 못한 것은 방법의 실행을 지연시키는 것이었다.
출처 : LosTechies
LINQ가하는 것처럼.
답변
대리자를 사용하여 함수 유형 변수 및 매개 변수를 선언 할 수 있습니다.
예
“자원 차용”패턴을 고려하십시오. 클라이언트 코드가 그 사이에 리소스를 “차용”하도록 허용하면서 리소스 생성 및 정리를 제어하려고합니다.
이것은 대리자 형식을 선언합니다.
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] );
} );
답변
델리게이트는 종종 하나의 방법으로 인터페이스 대신 사용될 수 있습니다. 일반적인 예로 관찰자 패턴이 있습니다. 다른 언어에서는 어떤 일이 발생했다는 알림을 받으려면 다음과 같이 정의 할 수 있습니다.
class IObserver{ void Notify(...); }
C #에서는 핸들러가 대리자 인 이벤트를 사용하여 더 일반적으로 표현됩니다. 예를 들면 다음과 같습니다.
myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
예를 들어 목록에서 항목 집합을 선택하는 경우와 같이 조건자를 함수에 전달해야하는 경우 대리자를 사용하는 또 다른 좋은 장소 :
myList.Where(i => i > 10);
위는 다음과 같이 작성할 수도있는 람다 구문의 예입니다.
myList.Where(delegate(int i){ return i > 10; });
대리자를 사용하는 것이 유용 할 수있는 또 다른 곳은 공장 함수를 등록하는 것입니다. 예를 들면 다음과 같습니다.
myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
이게 도움이 되길 바란다!
답변
나는 이것에 대해 정말 늦게 들어 왔지만 오늘 델리게이트의 목적을 파악하는 데 어려움을 겪었고 그들의 목적을 잘 설명하는 동일한 결과를 제공하는 두 개의 간단한 프로그램을 작성했습니다.
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);
}
}
Delegates.cs
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);
}
}
답변
약간 다른 용도는 반사 속도를 높이는 것입니다. 즉, 매번 리플렉션을 사용하는 대신 Delegate.CreateDelegate
메서드 (a MethodInfo
)에 대한 (형식화 된) 대리자를 만들고 대신 해당 대리자를 호출하는 데 사용할 수 있습니다 . 이것은 다음입니다 많은 검사가 이미 수행 된 것처럼, 빨리 호출 당.
를 사용하면 Expression
동일한 작업을 수행하여 즉석에서 코드를 만들 수도 있습니다. 예를 들어 Expression
런타임에 선택한 유형에 대한 + 연산자를 나타내는를 쉽게 만들 수 있습니다 (언어가 제공하지 않는 제네릭에 대한 연산자 지원을 제공하기 위해). ; 를 Expression
형식화 된 델리게이트로 컴파일 할 수 있습니다 .