2

疎結合構造を設計しています。String で表されるコードを介して、さまざまなアセンブリ/名前空間からクラスを呼び出したいと考えています。私の設計では、クライアントのビジネス ルールはそれぞれ異なるアセンブリにあり、相互に依存していません (1 つのクライアントは 1 つの DLL に対する比率です)。そのため、1 つのクライアントのビジネス ルールを更新しても、他のクライアントには影響しません。私の注意は、Factory Design の使用とActivator.CreateInstance()メソッドの使用にあります。

これはプロジェクトのセットアップです (2+n DLL)

 namespace Foundation; // where the interfaces/abstract resides
 namespace Factory; // has dependency on Foundation assembly
 namespace Client1; // client1's DLL, no dependency
 namespace Client2; // client2's DLL, no dependency
 The UI // only referenced to the Foundation and Factory not the Clients

実際のコード

 namespace Foundation
 {
   public interface IBusinessRules
   {
     string GetBusinessRule();
  }
 }

 namespace Client1 //DLL for client 1
 {
   public class BusinessRules : Foundation.IBusinessRules
   {
    public string GetBusinessRule()
    {
        return "Client1 Business Rule";
    }
   }
}

namespace Client2 //DLL for client 2
{
   public class BusinessRules : Foundation.IBusinessRules
   {
     public string GetBusinessRule()
     {
        return "Client2 Business Rule";
     }
   }
}


namespace Factory
{
  public static class Invoker<T> where T: Foundation.IBusinessRules
  {
    public static T FetchInstance(string clientCode) 
    {
        return (T)Activator.CreateInstance(Type.GetType(clientCode));   
    }
  }
}


 //sample implementation that generates unhandled Exception
 using Factory;
 using Foundation;
 static void Main(string[] args)
 {
      //the parameter is maintained in the database
       IBusinessRules objClient1 = Invoker<IBusinessRules>.FetchInstance("Client1"); 

       //should call Client1.BusinessRules method
        Console.WriteLine(objClient.GetBusinessRule());  
        Console.Read();

        objClient = Invoker<IBusinessRules>.FetchInstance("Client2");

        //should call Client2.BusinessRules method
        Console.WriteLine(objClient.GetBusinessRule()); 
        Console.Read();      
  }

私のサンプルが機能しない理由は何ですか? また、デザインを改善するための提案はありますか? 前もって感謝します。

使ってみてはどうですか

式.ラムダ

誰でも?

4

5 に答える 5

3

FetchInstance("Client.BusinessRules") を使用すると、すべてが同じアセンブリにある場合、コードが機能します。そうでない場合(設計どおり)、AssemblyQualifiedNameを指定する必要があります。

私はデザインを別の方法で行います。パラメータとして「Client1」のみを使用して呼び出しを維持しますが、ファクトリの実装を変更します。指定されたクライアントのアセンブリを (Assembly.Load() または Assembly.LoadFrom() を使用して) 動的に読み込み、次に clientAssembly.CreateInstance() を使用して型をインスタンス化します。

編集:粗いコードサンプル:

namespace Factory
{
  public static class Invoker<T> where T: IBusinessRules
  {
    public static T FetchInstance(string clientCode)
    {
        var clientAssembly = Assembly.LoadFrom(clientCode + ".dll");

        return (T)clientAssembly.CreateInstance(clientCode+".BusinessRules");
    }
  }
}

client-dll のクラス名がわからない場合は、clientAssembly.GetTypes() などを使用して、該当するタイプを検索する必要があります。

于 2010-09-16T14:29:56.587 に答える
2

あなたの助けのおかげで、私はついにそれを手に入れました!Factoryを変更するだけです

 namespace Factory
 {
    public static class Invoker<T> where T : Foundation.IBusinessRules
    {
        public static T FetchInstance(string clientCode)
        {
           Type objType = Type.GetType(clientCode + ".BusinessRules," + clientCode);
           return (T)Activator.CreateInstance(objType);

    }
}

しかし、リフレクションを使用しているため、その効率(パフォーマンスヒット)については疑問です..

于 2010-09-16T16:29:23.627 に答える
1

クラスの完全な名前を使用する必要があります。

例えば:

Type.GetType("System.Collections.Generic.Dictionary`2[System.String,[MyType,MyAssembly]]")
于 2010-09-16T14:05:46.933 に答える
0

外部アセンブリから型をロードする場合は、 を使用することをお勧めしActivator.CreateInstanceFromます。

var typeReference = Activator.CreateInstanceFrom(assemblyPath, fullyQualifiedClassName);
return typeReference.Unwrap() as T;
于 2010-09-16T14:47:57.973 に答える
0

展開後にビジネス ルールを dll として追加し、実行時に作成できるようにする場合は、アプリの下にビジネス ルール フォルダーを用意し、そのアプリにすべての dll をロードし、各 dll で IBusinessRules を実装するすべてのタイプを検索することをお勧めします。リフレクションを使用しています。型のハンドルができたので、名前に基づいて型を作成するのは簡単で、プロジェクトはスケールアウトします。

それか、クラスのアセンブリ修飾名をメソッドに渡します。

于 2010-09-16T15:23:35.627 に答える