c#.NET运行时对象类型

时间:2009-08-03 02:00:25

标签: c# .net reflection

我需要创建一个对象的实例,该对象的类型将在运行时确定。从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

    }

编辑:

理查德·伯格的解决方案在控制台应用程序中工作但不在上面的示例中,我已经转储了scan_class并验证了它获取值但是我一直收到此错误:

System.ArgumentNullException:值不能为null。 参数名称:type

以下是我更新的代码:

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

3 个答案:

答案 0 :(得分: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()。 / p>

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

答案 1 :(得分:0)

构造函数不是静态的,而且是公共的。我尝试了理查德的第二个建议没有运气,另一个空对象错误。

System.NullReferenceException:未将对象引用设置为对象的实例。    在SharedAuditSVC.Scan.StartScans(Int32 scan_id,String scan_name,Int32 scan_typeid,Int32 interval,SqlDataReader drActiveServers)中的C:\ shared_audit \ SVC \ SharedAuditSVC \ SharedAuditSVC \ Scan.cs:第84行

第84行是:

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

我显然做了一些可怕的错误,因为它没有得到“WindowsServiceAudit”的类型。该项目是一个Windows服务,我的问题涉及两个.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);

答案 2 :(得分: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动态化。谢谢你的帮助!