2009-08-03 4 views
3

オブジェクトのインスタンスを作成する必要があり、そのオブジェクトのタイプは実行時に決定されます。オブジェクトのタイプはSQLから引き出され、文字列値に設定されます。私はまた、インスタンス化するときにいくつかのパラメータを渡す必要があります。パラメータの数/タイプは毎回同じです(少なくとも今のところ)。これを達成するために使用する必要があるのは、Activator.CreateInstanceですか?どんな助けもありがとう。c#.NETランタイムオブジェクトタイプ

private void StartScans(int scan_typeid, SqlDataReader drActiveServers) 
    { 
     string sql = "SELECT scan_typeclass from scan_types WHERE scan_typeid = " + scan_typeid.ToString(); 
     sqlconn.Open(); 
     SqlCommand cmd = new SqlCommand(sql, sqlconn); 
     SqlDataReader drScanClass = cmd.ExecuteReader(CommandBehavior.CloseConnection); 

     string scan_class = drScanClass["scan_typeclass"].ToString(); 

     //Create object here 

    } 

EDIT:

リチャード・バーグのソリューションは、コンソールアプリケーションで働いていたが、上記の例では、私はscan_classをダンプしてきたではないし、その取得した値を検証したが、私はこのエラーを取得しておいてください。

System.ArgumentNullException:値にnullを設定することはできません。 パラメータ名:タイプ

は、ここに私の更新されたコードは次のようになります。

 try 
     { 
      string sql = "SELECT scan_typeclass from scan_types WHERE scan_typeid = " + scan_typeid.ToString(); 
      sqlconn3.Open(); 
      SqlCommand cmd = new SqlCommand(sql, sqlconn3); 
      SqlDataReader drScanClass = cmd.ExecuteReader(); 
      drScanClass.Read(); 

      string scan_class = drScanClass["scan_typeclass"].ToString(); 

      var type = Type.GetType(scan_class); 
      var myObj = Activator.CreateInstance(type, scan_id, scan_name, interval, drActiveServers); 

     } 
     catch (Exception e) 
     { 
      string sSource = "SharedAuditSVC"; 
      string sLog = "Application"; 
      string sEvent = e.ToString(); 

      if (!EventLog.SourceExists(sSource)) 
       EventLog.CreateEventSource(sSource, sLog); 

      EventLog.WriteEntry(sSource, sEvent); 
      EventLog.WriteEntry(sSource, sEvent, EventLogEntryType.Warning, 0); 

     } 

MEHが、私はそれが私はこの方法で私のカスタムクラスを呼び出して何も成功していなかったのに関連した範囲だと思います。私はそれの上で寝るよ... :)

作品:

WindowsServiceAudit WSA = new WindowsServiceAudit(scan_id, scan_name, interval, drActiveServers); 

は動作しません:

string scan_class = "WindowsServiceAudit";    

var type = Type.GetType(scan_class); 
var myObj = Activator.CreateInstance(type, scan_id, scan_name, interval, drActiveServers); 

答えて

7

をはい、まさに。

var type = Type.GetType(scan_class); 
var myObject = Activator.CreateInstance(type, constructorArg1, constructorArg2, [...]); 

// use myObject - you'll have to reflect on any properties that aren't derived from System.Object 

EDIT

コンストラクタは、静的または非公開である、またはあなたがコンストラクターズオーバーロードの解決にあいまいさを作成して渡しているパラメータ場合は、MethodInfo.Invokeを使用する必要があります()をActivator.CreateInstance()の代わりに使用します。タイプ名は完全修飾である

  1. var scan_class = "WindowsServiceAudit"; 
    var bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; 
    var constructorArgs = new object[] { scan_id, scan_name, interval, drActiveServers }; 
    var constructorTypes = from p in constructorArgs select p.GetType(); 
    
    var type = Type.GetType(scan_class);    
    var method = type.GetMethod(scan_class, bindingFlags, System.Type.DefaultBinder, constructorTypes.ToArray(), null); 
    var myObject = method.Invoke(null, bindingFlags, System.Type.DefaultBinder, constructorArgs, CultureInfo.CurrentCulture); 
    

    もいることを確認してください。リフレクションは "using"ステートメントについて何も知らない。

  2. タイプが存在するアセンブリがロードされます。必要に応じてAssembly.Load()を使用します。
0

コンストラクタは静的ではなく、パブリックです。私はリチャードの二番目の提案、運がない、別のnullオブジェクトエラーを試してみました。

System.NullReferenceException:オブジェクト参照がオブジェクトのインスタンスに設定されていません。 SharedAuditSVC.Scan.StartScansで Cで(のInt32 SCAN_ID、文字列scan_name、のInt32 scan_typeid、のInt32の間隔、SqlDataReaderのdrActiveServers):\ shared_audit \ SVC \ SharedAuditSVC \ SharedAuditSVC \ Scan.cs:ライン84

ライン84は、次のとおり

var method = type.GetMethod(scan_class, bindingFlags, System.Type.DefaultBinder, constructorTypes.ToArray(), null); 

「WindowsServiceAudit」のタイプが取得されていないため、私は明らかに間違っています。プロジェクトはWindowsサービスですが、私の質問には2つの質問があります。csソースファイル、Scan.cs、WindowsServiceAudit.cs。 Scan.csは、すべてのコードスニペットを取り出す場所です.WindowsServiceAuditは、インスタンス化しようとしているクラスです。

namespace SharedAuditSVC 
{ 
    class Scan 
    { 

namespace SharedAuditSVC 
{ 
    public class WindowsServiceAudit 
    { 

両方とも同じ名前空間に属していますので、どちらも混乱しています。また、私は再び、私は次の操作を行って、うまくそれを作成することができます明確にすることがSharedAuditSVC.WindowsServiceAudit

としてそれを参照してみました:

WindowsServiceAudit WSA = new WindowsServiceAudit(scan_id, scan_name, interval, drActiveServers); 
+0

実際にあなたがその行にそれを作った場合は、コンストラクタメソッドではなく、ok型が見つかります。 type.GetConstructors()およびtype.GetConstructors(bindingFlags)を呼び出し、返される内容を確認してください。良く/悪いことに、リフレクションには常に多くの試行錯誤が必要です。ヒント:VSデバッガのイミディエイトウィンドウを使用して、ダイナミックタイプを即座に突き止めることができます。 (または私の好み:Powershell)。 –

+0

私はあなたの助けを受けてどこかに行っていると思います。インスタンス化しようとしていたクラスの前に名前空間を置く必要がありました。 var scan_class = "SharedAuditSVC.WindowsServiceAudit"; これは私の問題の1つでした。今では、type.GetMethod()の代わりにtype.GetConstructors()を使用してソリューションを実装しようとしています。 – jw0rd

+0

名前空間の前には、型名を完全修飾するという意味があります。 –

0

は最後に、私は今、それを右:)

string sql = "SELECT scan_typeclass from scan_types WHERE scan_typeid = " + scan_typeid.ToString(); 
sqlconn3.Open(); 
SqlCommand cmd = new SqlCommand(sql, sqlconn3); 
SqlDataReader drScanClass = cmd.ExecuteReader(CommandBehavior.CloseConnection); 
drScanClass.Read(); 

var scan_class = "SharedAuditSVC." + drScanClass["scan_typeclass"].ToString(); 

Type[] argTypes = new Type[] { typeof(System.Int32), typeof(System.String), typeof(System.Int32), typeof(System.Data.SqlClient.SqlDataReader) }; 
object[] argVals = new object[] { scan_id, scan_name, scan_typeid, drActiveServers }; 
var type = Type.GetType(scan_class); 
ConstructorInfo cInfo = type.GetConstructor(argTypes); 
var myObject = cInfo.Invoke(argVals); 

を得ました最終的にargsを動的にすることさえできます。助けてくれてありがとう!

+0

うれしかった!リフレクションの楽しみじゃない? (eek!) –