簡體   English   中英

C#.NET運行時對象類型

[英]c# .NET runtime object type

我需要創建一個對象的實例,並且該對象的類型將在運行時確定。 對象的類型從SQL中提取並設置為字符串值。 我還需要在實例化它時傳遞一些參數。 參數的數量/類型每次都相同(至少現在是相同的)。 我需要使用什么來完成此任務,Activator.CreateInstance? 任何幫助,將不勝感激。

    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

    }

編輯:

理查德·貝格(Richard Berg)的解決方案在控制台應用程序中工作,但在以上示例中不起作用,我轉儲了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);

        }

嗯,我認為這與范圍有關,盡管我沒有通過這種方法成功調用自定義類。 我會睡覺的.. :)

作品:

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

對,就是這樣。

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()。

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

System.NullReferenceException:對象引用未設置為對象的實例。 在C:\\ shared_audit \\ SVC \\ SharedAuditSVC \\ SharedAuditSVC \\ Scan.cs:line 84的SharedAuditSVC.Scan.StartScans(Int32 scan_id,字符串scan_name,Int32 scan_typeid,Int32間隔,SqlDataReader drActiveServers)

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

終於正確了:)

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動態化。 謝謝您的幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM