2009-08-03 70 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); 

现在我甚至可以使参数动态化,最终。谢谢您的帮助!