2009-08-03 83 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 

    } 

編輯:

理查德·伯格的解決方案在一個控制檯應用程序而不是在上面的例子中工作過,我甩scan_class並驗證其獲得的值,但是我不斷收到此錯誤:

System.ArgumentNullException:值不能爲空。 參數名:類型

這裏是我更新的代碼看起來像:

 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); 

     } 

咩,我認爲這是範圍相關的,雖然我沒有成功通過這種方法叫我的自定義類。我會認真考慮的.. :)

作品:

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 

編輯

如果構造函數是靜態的還是非公開的,或者你通過創建在車隊重載歧義的參數,那麼你就需要使用MethodInfo.Invoke ()而不是Activator.CreateInstance()。

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); 

還要確保:

  1. 的類型名稱是完全合格的。反思並不知道「使用」語句的任何內容。
  2. 加載類型所在的程序集。如有必要,使用Assembly.Load()。
0

該構造函數不是靜態的並且是公共的。我試着理查德的第二個建議,沒有運氣,另一個空對象錯誤。

System.NullReferenceException:未將對象引用設置爲對象的實例。 在用C SharedAuditSVC.Scan.StartScans(的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)。 – 2009-08-03 18:40:40

+0

我想我得到某處感謝您的幫助。我不得不把名字空間放在我試圖實例化的類的前面。 var scan_class =「SharedAuditSVC.WindowsServiceAudit」; 這是我的問題之一。現在我只是試圖用type.GetConstructors()而不是type.GetMethod() – jw0rd 2009-08-03 20:48:55

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); 

現在我甚至可以使參數動態化,最終。謝謝您的幫助!