ホームページ >バックエンド開発 >C#.Net チュートリアル >C# におけるリフレクションとダイナミックの最適な組み合わせの例

C# におけるリフレクションとダイナミックの最適な組み合わせの例

黄舟
黄舟オリジナル
2017-09-07 13:32:471579ブラウズ

この記事では、主に C# におけるリフレクションとダイナミックの最適な組み合わせのサンプル コードを紹介します。必要な方は参考にしてください。

リフレクション テクノロジは C# で広く使用されています。理解している場合は、次の段落の説明を読んでください。そうでない場合は、次の段落をスキップしてください。広告: 私の記事を気に入ってくださったお友達は、私のブログに注目してください。これは私の執筆モチベーションの向上にも役立ちます。

反省:美しい女性やハンサムな男性に背を向けているが、振り返って注意深く観察したり研究したりすることができないとき(まったくの架空の話、偶然や類似点)、小さな鏡があなたのニーズを満たすことができます。 C# プログラミングのプロセスでは、他の人が作成した DLL クラス ライブラリを使用したいのに、プログラムのドキュメントがないという同じような状況に遭遇することがよくあります。このとき、C# ランタイムが提供する関数を通じて、 dll クラス ライブラリを使用できます。ライブラリをプログラムにロードし、dll のすべての部分を学習します。これは C# での反映です。

個人的に、リフレクションの最も顕著な利点または合理性は、プログラムの元のコードを変更することなく、プログラム関数の動的調整 (実行時の動的オブジェクトの作成) だと思います。

例:


 interface IRun {
  void Run();
 }
 class Person : IRun
 {
  public void Run()
  {
   Console.WriteLine("走,去LOL啊!");
  }
 }
 class Car : IRun
 {
  public void Run()
  {
   Console.WriteLine("呜...........");
  }
 }
 class Program
 {
  static void Main(string[] args)
  {
   IRun e = new Person();
   e.Run();
   Console.ReadLine();
  }
 }

上記 Run 機能は必ずしも person によって実行されるわけではありません。Car が必要な場合もあれば、Personal が必要な場合もあります。一般的な解決策は、次のように if などの判断構造を追加することです:


 static void Main(string[] args)
  {
   Console.WriteLine("请输入:Car或Person");
   string type = Console.ReadLine();
   IRun e = null;
   if ("Car" == type)
   {
    e = new Car();
   }else if("Person" == type)
   {
    e = new Person();
   }
   if(null != e)
    e.Run();
   Console.ReadLine();
  }

この構造は現在のニーズを解決しますが、堅牢ではありません。 IRun インターフェースの実装と関連クラスの継承の増加に伴い、上記の判定構造も急速に増大するでしょう。オブジェクト指向プログラミングと設計パターンが従う主要な原則の 1 つは、変換をカプセル化することであるため、上記のプログラムは変更にうまく対処できません。ここでは「デザインパターン」の知識は関与しません。そのため、以下のサンプルコードは上記のプログラムを簡略化するためのものであり、意図的にデザインパターンに関する知識を適用するものではありません。以下の通り:


 static void Main(string[] args)
  {
   Console.WriteLine("请输入:Car或Person");
   string type = Console.ReadLine();
   string classPath = String.Format("namespace.{0}", type);
   IRun e = Activator.CreateInstance(null, classPath).Unwrap() as IRun;

   if(null != e)
    e.Run();
   Console.ReadLine();
  }

上記の変更後、プログラムはユーザーの入力に基づいて Activator.CreateInstance を介して IRun のインスタンスを作成できるようになり、IRun 実装者の数が増加してもプログラムは変更されなくなります。反省によって上記のメリットが得られる、これが「反省の存在の合理性」だと私は考えています。

Activator と Assembly は、オブジェクトを作成するためのリフレクション メソッドを実装します

リフレクション メソッドでのオブジェクトの作成は、Activator.CreateInstance (静的) と Assembly.CreateInstance (非静的) を通じて実現できますが、そのうち Assembly.CreateInstance は依然として呼び出されます内部的には Activator.CreateInstance。

動的に作成されるタイプ オブジェクトが現在のアセンブリ内にあるかどうかに応じて、リフレクションによって作成されるオブジェクトは、アセンブリ内でのタイプ オブジェクトの作成とアセンブリ外でのタイプ オブジェクトの作成に分けられます。

アセンブリ内に型オブジェクトを作成する


  private static void ReflectionIRun1(string className)
  {
   string classPath = String.Format("namespace.{0}", className);
   //参数 null ,指出所要创建类型对象位于当前程序集 
   var handler = Activator.CreateInstance(null, classPath);
   IRun e = (IRun)handler.Unwrap();
   Console.WriteLine(e.Run());
  }
  private static void ReflectionIRun2(string className)
  {
   string classPath = String.Format("namespace.{0}", className);
   //typeof(IRun).Assembly 获取 IRun 类型所在的程序集
   object obj = typeof(IRun).Assembly.CreateInstance(null, classPath);
   IRun e = (IRun)obj;
   Console.WriteLine(e.Run());
  }

アセンブリの外に型オブジェクトを作成する

以下に示すように、クラス ライブラリ (別のアセンブリ) をプロジェクトに追加します:

ボスを追加するクラスは次のとおりです。


namespace Lib
{
 public class Boss
 {
  private string name = "老大";
  
  public string Name{
   get {return name;}
  }
  public string Talk()
  {
   return "你们都被开除了......";
  }
  //老板不会算账,总是多付钱,所以很有自知之明的将Payfor设为private,防止外部人员调用
  private int Payfor(int total)
  {
   return total + 10;
  }
 }
}

Boss オブジェクトを取得する前に、まず Lib への参照を追加します。 取得の例は次のとおりです。


 private static void ReflectionBoss1()
  {
   string classPath ="Lib.Boss";
   //"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义)
   var handler = Activator.CreateInstance("Lib", classPath);
   Boss b = handler.Unwrap() as Boss;
   Console.WriteLine(b.Talk());
  }
  private static void ReflectionBoss2()
  {
   string classPath ="Lib.Boss";
   //Assembly.Load("Lib") 加载的程序集(即要创建的对象类型在哪个程序集中定义)
   var assembly = Assembly.Load("Lib");
   Boss b = (Boss)assembly.CreateInstance(classPath);
   Console.WriteLine(b.Talk());
  }

CLR がアセンブリを検索して配置する方法については、リフレクション中にロードされるため、リフレクションに関する知識については MSDN を参照してください。

リフレクション アクセス フィールドとメソッド (プロパティ) の呼び出し

リフレクションは、オブジェクトを動的に作成するのに役立つだけでなく、C# のバージョンが異なるため、特定のメソッドが動的にアクセスするのにも役立ちます。変更または拡張についての詳細な内容については、MSDN を参照してください。以下は簡単な例です (標準的な使用法)。

上司の名前を変更します。例: 」 '


 private static void ReflectionBoss1()
  {
   string classPath = "Lib.Boss";
   //"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义)
   var handler = Activator.CreateInstance("Lib", classPath);
   Boss b = handler.Unwrap() as Boss;
   //关键代码
   FieldInfo f = b.GetType().GetField("name", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
   f.SetValue(b, "小二");
   Console.WriteLine("{0}:{1}", b.Name, b.Talk());
  }

出力:

上司にお金を支払わせる:


private static void ReflectionBoss1()
  {
   string classPath = "Lib.Boss";
   //"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义)
   var handler = Activator.CreateInstance("Lib", classPath);
   Boss b = handler.Unwrap() as Boss;
   //关键代码
   MethodInfo method = b.GetType().GetMethod("Payfor", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance);
   object money = method.Invoke(b, new object[] { 10 });
   Console.WriteLine("DW039:老大给我报销10元钱车费......");
   Console.WriteLine("{0}:.....,算不清了,给你这些吧。",b.Name);
   Console.WriteLine("DW039:......");
   Console.WriteLine("{0}:{1}", b.Name,money);
   Console.WriteLine("DW039:老大你真棒!");
  }

出力:

ダイナミックとリフレクション 2なぜなら、Reflection は実行時の型操作であるため、プログラミング時に型の不確実性の問題に直面するからです。前回の記事「C# 匿名オブジェクト (匿名型)、Var、動的型 Dynamic」によると、動的動的型と私たちが作成したリフレクション プログラムを組み合わせることで、プログラム ロジックを大幅に最適化できます (保護レベルによって制限されているコードへのアクセスは制限されません)この範囲)。

上記のコードの最適化:

private static void ReflectionBoss1()
  {
   string classPath ="Lib.Boss";
   var handler = Activator.CreateInstance("Lib", classPath);
   dynamic b = handler.Unwrap();
   Console.WriteLine(b.Talk());
  }
  private static void ReflectionBoss2()
  {
   string classPath ="Lib.Boss";
   var assembly = Assembly.Load("Lib");
   dynamic b = assembly.CreateInstance(classPath);
   Console.WriteLine(b.Talk());
  }

動的動的型オブジェクト b を使用してリフレクションを呼び出し、直接呼び出すことができるオブジェクトのプロパティとメソッドを取得することで、頻繁な型変換操作を排除します。

リフレクションの一般的なアプリケーションシナリオ

アプリケーション シナリオ 私が最も印象に残ったのは、MS Petshop の例です。SQL Server データベースから Oracle データベースに切り替えると、リフレクションはさまざまなデータ アクセス層を取得します。ただし、実際のプロジェクトでデータベースが途中で切り替わる状況に遭遇したことはありません。他のアプリケーション シナリオも基本的には上記の例と同様です。さらに多くのアプリケーション シナリオを見つけた場合は、3ks を追加してください。

リフレクションの長所と短所

利点: リフレクションによりプログラムがより柔軟になります

欠点: リフレクションの実行が比較的遅い

リフレクションが通常のプログラムよりも遅いことについては、テストしていませんし、行う予定もありません。現実には、Ms はダイナミックの使用を推奨しており、Mvc は人気があり、継続的に CLR を最適化し、マシンのパフォーマンスを向上させているため、開発中にリフレクション パフォーマンスの問題をあまり考慮する必要はありません。作成したプログラムの実行速度にボトルネックがある場合 (プログラムが適切に作成されていることをまず確認する必要があります)、データベースの最適化、データ キャッシュ、Web キャッシュ、負荷分散などのテクノロジを研究する方が現実的だと思います。

以上がC# におけるリフレクションとダイナミックの最適な組み合わせの例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。