序文
代理人(代理人)とイベント(イベント)について話をする、Benpianの形を取ることは重要な部分(Microsoftのドキュメントの中国は、Microsoftの委任にドキュメントの英語翻訳を読んだことがあるなぜ彼らが持っている中国の感触を読んでいるので、私に聞かないんです失読症 - - )+それが合わない、または白のデリゲートを使用していない、彼らの理解をまとめます。
信頼がイベントのイベントデリゲートの基本であり、かつので、なぜ一緒に代表者とのイベントが、彼らは簡単に混乱している必要があります。
.NETでバインディング(バインディング)機構を提供することに委託:委託位置にオリジナルドキュメントで。
System.Delegateとデリゲートキーワード
デリゲート型を定義します。
我々delegate
キーワードの始まり、それはあなたがデリゲートを使用する主な方法ですので。あなたがキーワードを使用するとdelegate
、コンパイラは、その呼び出し方法のいくつかにマップのコードを生成Delegate
し、MulticastDelegate
クラスのメンバーを。
より多くの同様のメソッドのシグネチャを定義された構文の定義を委託、あなただけの戻り値の型とアクセス権の間でキーワードを追加する必要がありますdelegate
。
引き続き使用するList.Sort()
方法を私たちの例として、(ドキュメントは、前の例を使用している)、最初のステップは、比較のデリゲート型を作成することです:
public delegate int Comparison<in T>(T left, T right);
上記のステートメントによって、コンパイラが生成Comparison
から派生したクラスをSystem.Delegate
。このクラスは、2つのパラメータ(すなわち、署名、及び同じ)が存在する、整数を返すメソッドを含みます。
あなたはクラス内で、名前空間の中に、グローバル名前空間には、デリゲートを定義することができます。(もちろん、それがグローバル名前空間で定義された委員会にはお勧めしません)
コンパイラは、クラスを追加するために、生成するプログラムを削除し、ユーザーは、インスタンスのリストから、呼び出しに削除方法をクラスを追加することができます。コンパイラの施行は、追加メソッドのシグネチャは、宣言が削除された署名方式と一致して使用します。
例文デリゲート
あなたはデリゲート型を定義した後、あなたは、デリゲートのインスタンスを作成することができます。作成と他の変数に差がないのインスタンスを作成します。
public Comparison<T> comparator;
変数のcomparator
タイプは、我々が以前に定義されたデリゲート型ですComparison<T>
。変数と同様に、我々は、ローカル変数のデリゲート、メソッドのパラメータとしてデリゲート変数を宣言することができます。
流通、追加と削除方法
各デリゲートのインスタンスは、コールリストが含まれている、コールリストは、デリゲートのインスタンスに割り当てられているすべてのメソッドが含まれています。
あなたは、デリゲートのインスタンスにメソッドを割り当てたいあなたが最初のメソッドのシグネチャがデリゲート型の定義と一致して定義する必要があります。以下にすることがわかるCompareLength
メソッドシグネチャデリゲート定義、及びその内部の同じタイプであるstring
クラスメソッド。
//这是一种用lambda表达式定义的方法
private static int CompareLength(string left, string right) =>
left.Length.CompareTo(right.Length);
関係を作成するためにはlist.sort()メソッドに、この方法で渡さ:
//使用上述定义的方法名。
phrases.Sort(CompareLength);
//这里不用纠结为什么是这样传入,它只是docs的一个例子,其内部肯定有
//comparator = CompareLength;
//这样的形式
ここで、パラメータとしてメソッド名は、参照方法は、基準デリゲート呼び出し対象として使用することができる変換するコンパイラを指示し、及び方法は、追加対象として起動されます。次のようにそのコアがあります
//左边是委托变量,右边是方法名称
comparator = CompareLength;
宣言Comparison
タイプ・物流の変数を以下のとおりであります:
public Comparison<string> comparer = CompareLength;
private static int CompareLength(string left, string right) =>
left.Length.CompareTo(right.Length);
目標は、この方法は非常に短い道を委任する場合もちろん、あなたもラムダを使用することができます
public Comparison<string> comparer = (left, right) =>
left.Length.CompareTo(right.Length);
ここを参照してくださいシングルターゲット変数手数料に追加する方法がありますが、手数料は、デリゲートの呼び出し変数のリストに追加する複数の方法をサポートしています。
コールデリゲート
この下の変数手数料+パラメータの形式で名前によって、私たちは、メソッドのリストに追加メソッドのデリゲートを呼び出します。
int result = comparator(left, right);
任意の追加にない場合はcomparator
、変数の方法、上記のコードを送信する必要がありますNullReferenceException
。
MulticastDelegate
System.MulticastDelegate
それはSystem.Delegate
、単一の直接のサブクラス。C#が禁止Delegate
とMulticastDelegate
。使用している場合delegate
、あなたがデリゲート型を宣言するときに定義するキーワードを、C#コンパイラは、作成MulticastDelegate
派生したインスタンスを。セキュリティの考慮事項のタイプの場合、コンパイラは、特定の委譲クラスを作成します。
メソッドのほとんどは、デリゲートのインスタンスで使用する場合Invoke()
とBeginInvoke()/EndInvoke()
、Invoke()
デリゲートの特定のインスタンスに接続されているすべてのメソッドで呼び出します。
強く型付けされたデリゲート
我々は使用することができ、前のセクションで見たdelegate
特定のデリゲート型のキーワードを作成します。
あなたが別のメソッドのシグネチャを必要とするときは、新しいデリゲート型を作成します。それぞれの新しい機能は、新しいデリゲート型を必要とするいくつかの時間後の仕事は、退屈になることができます。
幸い、.NETコアフレームワークはいくつかの種類が含まれているデリゲート型を必要なときに、あなたはそれらを再利用することができます。
これらのタイプの最初のですAction
。
public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
Action
その主要な多くの変形、16個のまでのパラメータを含みます。Action
戻り値なし。
二番目に人気がありますFunc
:
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
Func
16個の入力までのパラメータを委託、結果の型は、常に最後の引数の型です。Func
値を返します。
もう一つはPredicate<T>
:
public delegate bool Predicate<in T>(T obj);
いずれかのために、あなたは、気づくことができるPredicate
デリゲート型が等しい持つFunc
デリゲート型を:
Func<string, bool> TestForString;
Predicate<string> AnotherTestForString
、今、あなたは、私は別のブログの記事に記載されている使用法のこれらの特別なデリゲート型のいずれかの新しい機能のための新しいデリゲート型を定義する必要はありませんが、今は想像することができAction
、次のように使用量は次のようになります。
Action showMethod = SomeMethod();
showMethod();
委託コモンモード
ソフトウェア設計に含まれるコンポーネント間の結合を最小化する機構を提供することに委託。
LINQ
これは、この設計の良い例です。LINQ
すべての機能のクエリ式パターン手数料に依存しています。以下の簡単な例を考えてみましょう。
var smallNumbers = numbers.Where(n => n < 10);
//括号中是Func的lambda写法,Action和Func的用法我将在另一篇博客中介绍,这里你只需要知道括号中传入的是一个已经赋值的委托实例。
デジタルフィルタのみ10以上のように、上述したシーケンスの例。Where
この方法は、デリゲート要素が除外される順序を決定するために使用されます。
Where
プロトタイプの方法は次のとおりです。
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> souce, Func<TSource, bool> predicate);
この例では、手数料はコンポーネント間の結合を低減する方法を示し、あなたが特定のクラスの蓄積から派生作成する必要があり、あなたは、特定のインターフェイスを実装する必要はありません。あなたがする必要がある唯一のものは、手元の作業を達成するための方法を提供することにあります。
独自のコンポーネントを作成するためにプロキシを使用
(ここで、ドキュメントは、実際にデリゲートを使用する方法を説明するために例を挙げ)
のは、大規模なシステムで使用することができますログメッセージのコンポーネントを定義し、このコンポーネントは、多くの共通の特徴を持っている、それは、システム内のどこからでもメッセージを受信しましょう。これらのメッセージは、異なる優先順位を持っています。
初回
オリジナルの実装はこれです:私たちはメッセージを受信している、その後、デリゲートを使用して、コンソールに書き込まれたメッセージ。
public static class Logger
{
//Action委托实例
public static Action<string> WriteMessage;
//对外接口
public static void LogMessage(string msg)
{
//调用委托上的方法
WriteMessage(msg);
}
}
public static class LoggingMethods{
//将信息打印到控制台的方法
public static void LogToConsole(string message)
{
Console.Error.WriteLine(message);
}
}
//委托实例赋值,这句话一般发生在LoggingMethods的构造器中
Logger.WriteMessage += LoggingMethods.LogToConsole;
デリゲートのインスタンスメソッドに取り付けた、インスタンスメソッドであってもよいし、あなたはまた、すべてのアクセス権を持つことができます。
書式付き出力
するにはLogMessage
、ログより構造化メッセージを作成するために、いくつかのパラメータのメソッドを追加します。
public enum Severity{
Verbose,
Trace,
Information,
Warning,
Error,
Critical
}
使用してSeverity
メッセージのフィルタリング印刷を。
public static class Logger
{
public static Action<string> WriteMessage;
public static Severity LogLevel {get;set;} = Severity.Warning;
public static void LogMessage(Severity s, string component, string
msg)
{
//继续增加筛选功能
if (s < LogLevel)
return;
var outputMsg = $"{DateTime.Now}\t{s}\t{component}\t{msg}";
WriteMessage(outputMsg);
}
}
ここでは、それを見ることができLogger
、我々が変更されたときに非常に、任意の出力クラスを失うと結合されたLogger
印刷条件を、特定の完全デリゲートは変更する必要はありません。実際には、ログアセンブリ委託結合することによって、異なる出力クラスであってもよく、それらは完全に再構築する必要はありません。
第2のエンジン出力
レコードエンジン出力ファイルにメッセージを追加してみましょう。これは、ラッパークラスのファイル操作である、もう少し複雑であり、各ファイルは(これ性を保証ディスクにフラッシュするすべてのデータを生成した後、各メッセージという)常にオフ書かれていることを確実にするために。
public class FileLogger
{
private readonly string logPath;
public FileLogger(string path)
{
logPath = path;
Logger.WriteMessage += LogMessage;
}
public void DetachLog() => Logger.WriteMessage -= LogMessage;
// make sure this can't throw.
private void LogMessage(string msg)
{
try
{
using (var log = File.AppendText(logPath))
{
log.WriteLine(msg);
log.Flush();
}
}
catch (Exception)
{
// Hmm. We caught an exception while
// logging. We can't really log the
// problem (since it's the log that's failing).
// So, while normally, catching an exception
// and doing nothing isn't wise, it's really the
// only reasonable option here.
}
}
}
このように作成した後、それをインスタンス化することができ、そしてそれは、その設定LogMessage
方法が接続されていますLogger
。
var file = new FileLogger("log.txt");
ことを意味します(コンソールやファイルへの出力)を同時に出力ログをこれらの2つの方法を添付することができます。
var fileOutput = new FileLogger("log.txt");
Logger.WriteMessage += LogToConsole;
後も同じアプリケーション内で、また、システム上の他の問題を引き起こすことなく削除することができる方法
Logger.WriteMessage -= LogToConsole;
もう一度思い出させ、あなたは他のインフラストラクチャを構築する必要はありません出力の様々な方法をサポートするために必要な、これらの方法は、デリゲートのインスタンスに追加されたリストに、それを呼び出すためだけの方法です。
、我々は、デリゲートメソッドが例外をスローしないようにする必要があり、例外をスローするのデリゲートのインスタンスのいずれかのメソッド呼び出しリストならば、他のメソッドが呼び出され、リスト上で起動されませんのでご注意ください。
ヌル委員会
ときにWriteMessage
時間が方法を添付されていない、それが呼び出しをトリガーしますNullReferenceException
最後に、更新しましょうLogMessage
、それは任意のデリゲートメソッドが存在しない場合に堅牢であることを確実にするための方法を。
public static void LogMessage(string msg)
{
WriteMessage?.Invoke(msg);
}
(この場合のWriteMessageで)左オペランドの操作がヌルであるが、条件演算子をヌルとき(?)短絡、デリゲートメソッドを呼び出そうとしない手段となります。
概要
設計にデリゲートを使用することによって、異なる成分は非常に緩く一緒に結合することができます。これにはいくつかの利点を提供します。あなたは簡単に新しい出力メカニズムを作成し、システムログにそれらを添付することができます。ログメッセージの書き込み方法:これらのメカニズムは、1つの方法だけを必要としています。この設計では、新機能を追加することで、非常に強力な柔軟性を持っています。任意の作家が唯一のメソッドのパラメータと戻り値の同じ種類を実装する必要があります。この方法は、静的またはインスタンスメソッドであってもよいです。これは、パブリック、プライベートまたはその他の合法的にアクセスすることができます。