现有两个类class1和class2,两个类中各有static的meth()方法。OK,现在index.cs文件中需要对刚才两个类的静态方法,进行动态调用。如何做?请不要告诉我,直接用class1.meth()来调用,这个地球人都知道。因为刚才举的只是两个类,但事实上我的项目中有上百个这样的类,需要动态来直接判断,动态直接调用。在网上找到这样一段代码,据说是动态类名创建实例的,代码可以通过编译,但是不知道如何调用到方法?
public object GetInstanceByName( string className )
{
 object obj;
 try
 {
  obj = Activator.CreateInstance( Type.GetType( className ) );
 }
 catch( Exception e )
 {
  throw new Exception( "动态创建实例失败 \n\n=> " + className  , e );
 }
 return obj;
}还有,在网上搜索了下,好象可以用反射机制来做?但搜索到的文章都比较复杂难懂,希望有个高人按照我上面的要求,给几句关键代码。谢谢!

解决方案 »

  1.   

    获取自定义类型所在的程序集:
      System.Reflection.Assembly.Load(string assemblyString)
      System.Reflection.Assembly.LoadFrom(string assemblyFile)  当dll在特殊的路径
    获取类型:
      System.Object.GetType()
      System.Reflection.Assembly.GetType(string name)
    获取方法的实例对象:
      System.Type.GetMethod(string name)
    根据实例对象执行方法:
      System.Reflection.MethodBase.Invoke(object obj, object[] parameters)
      

  2.   

    参看
    http://blog.csdn.net/knight94/archive/2006/04/10/657527.aspx
      

  3.   

    其中,对于Invoke,如果方法是stati的,那么obj参数应该为null。
      

  4.   

    namespace TestStatic
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        private void Form1_Load(object sender, EventArgs e)
            {
                Test();
            }        private void Test()
            {
                Type type = Type.GetType("TestStatic.A");
                MethodInfo mi = type.GetMethod("Test");
                object o = mi.Invoke(null, new object[] { "123" });
            }
        }
        public class A
        {
            public static string Test(string a)
            {
                Console.WriteLine("A.Test() is run;"+a);
                return a;
            }
        }
    }
      

  5.   

    或者使用接口,
    interface IWay
    {
    public virtual Meth();
    }所有的类都从上面接口派生。
    public IWay GetInstanceByName( string className )
    {
     IWay obj;
     try
     {
      obj = (IWay)Activator.CreateInstance( Type.GetType( className ) );
     }
     catch( Exception e )
     {
      throw new Exception( "动态创建实例失败 \n\n=> " + className  , e );
     }
     return obj;
    }
    IWay iway = GetInstanceByName(...);
    iway.Meth();
      

  6.   

    刚测试了zjlion(晴海) 的代码,在VS2003中成功了,可是在VS2005中一直失败!我的项目是2005的,这下咋办?
    在2005中一直报错未将对象引用设置到对象的实例。 
    说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 异常详细信息: System.NullReferenceException: 未将对象引用设置到对象的实例。源错误: 
    行 25:         {
    行 26:             Type type = Type.GetType("testGetClass.A");
    行 27:             MethodInfo mi = type.GetMethod("Test");//这句老出错
    行 28:             object o = mi.Invoke(null, null);
    行 29:         }
     
      

  7.   

    to 
    行 27: MethodInfo mi = type.GetMethod("Test");//这句老出错
    行 28: object o = mi.Invoke(null, null);我的文章没说明吗,你需要在使用的时候加上BindingFlags说明,例如
       object objReturn = yourType.InvokeMember(
           "Test",
            BindingFlags.DeclaredOnly |
            BindingFlags.Public |
            BindingFlags.Static | BindingFlags.InvokeMethod,
            null,
            null,
            new object[]{ yourpara } );
      

  8.   

    Knight94(愚翁) ,我的不是引用DLL。而是在VS2005中建了一个项目,明不?类也在这个项目中。
    而且,我不是用winForm,而是asp.net。在VS2005中新建一个asp.net项目,类文件都没有命名空间的呀!如何办?
      

  9.   

    to 我的不是引用DLL。而是在VS2005中建了一个项目,明不?类也在这个项目中。
    而且,我不是用winForm,而是asp.net。在VS2005中新建一个asp.net项目,类文件都没有命名空间的呀!如何办?对于反射来说,主要是获得Type,你既然不需要加载Assembly,就可以把这部分省掉。反射对于winform和asp.net来说没有区别。如果没有命名空间,你在获得类型的时候不加上即可。
      

  10.   

    也就是说  Type type = Type.GetType("A"); 仅仅打上类名,而没有命名空间时会出错。VS2005是不是有另外的调用方法呢?
      

  11.   

    to 也就是说 Type type = Type.GetType("A"); 仅仅打上类名,而没有命名空间时会出错。VS2005是不是有另外的调用方法呢?你可以如下试试
    Type type = typeof( yourClassName );
      

  12.   

    例如:
    public class A
    {
       public static void Test()
       {
        }
    }//Call
    Type type = typeof( A );
      

  13.   

    typeof(A)是成功了,可是,跟我的初衷完全相反了!因为我的类名需要string 动态调用。现在,又回到原来的地方了。绕了一个大圈,类名依然不能动态调用。
      

  14.   

    你可以看看typeof(A).ToString是什么东西,和你写的“A”有什么区别。
      

  15.   

    typeof(A).ToString 等于 "A"
    但是,关键是我现在想通过字符串来动态调用类,你明我的意思么?而不是通过类名来知道字符串,请指教!
      

  16.   

    你能否告诉我,有什么办法,可以让 typeof(A) 中的 A 可以根据外部的string 变量来动态改变?只要能解决这个,我就可以结帖了。
      

  17.   

    如下的代码在win下是可以的,你可以试试:
    Assembly assembly = Assembly.GetExecutingAssembly();
    Type type = assembly.GetType( "A" );
      

  18.   

    对了,你有安装VS2005么?建个ASP.Net页试下。唉,现在卡在这里了,下面都不知如何进行了。
      

  19.   

    Type.GetType的四一个参数为Type.AssemblyQualifiedName,包括程序集名称,类似
     Class2, App_Code.ps5u79wb, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null因此,你可以先用typeof(YourClass)查看后缀是什么,然后再用Type.GetType(YourClass+后缀)
      

  20.   

    楼上的,不太明白你说的。但是,我用了 Type.GetType(YourClass+typeof(YourClass))依然失败。
      

  21.   

    其实,现在总结最大的问题是,VS2005中ASP.Net没有命名空间所致。但是,如何解决?因为在VS2003中,是成功的。
      

  22.   

    新建的类文件,我都放在App_Code目录下了。
      

  23.   

    jun_01(无名小卒) 能写几段示例代码吗?
      

  24.   

    你还是没明白赫赫,可以这样:比如说你的类名是Class1,Class2....string tmp = typeof(Class1).AssemblyQualifiedName;
    tmp = tmp.Substring(tmp.IndexOf(","));
    Type t = Type.GetType("Class2" + tmp);t.InvokeMember("MethodName", BindingFlags.InvokeMethod | BindingFlags.Static, null, null, null);
      

  25.   

    string tmp = typeof(Class1).AssemblyQualifiedName;
            tmp = tmp.Substring(tmp.IndexOf(","));
            Type t = Type.GetType("Class2" + tmp);        t.InvokeMember("Write", BindingFlags.InvokeMethod | BindingFlags.Static|BindingFlags.Public, null, null, null);
      

  26.   

    如果方法是private的,需要指定BindingFlags.NonPublic
      

  27.   

    昏~楼上的代码中的Class1是类名?怎么又有Class2?两者关系是?
    我发现还是有很多人不理解我的需要,zjlion(晴海) 的代码正合我意!大家请先运行他的代码,我要的是他的效果!但是,现在新的问题出来了:在VS2005上新建一个ASP.Net项目却无法运行他的代码(现在我估计是2005里没有命名空间所致的),明白了吗?请高人们指点!在指点前,请先运行晴海的代码。
      

  28.   

    就是这段,最合我意了!可是只能在VS2003下运行!而且我要的是ASP.Net,在VS2005下使用。但出错了,请高人解救!不要再提出其它新的解决方法了,我研究了半天,发现净是跑题的代码,谢谢。
    namespace TestStatic
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        private void Form1_Load(object sender, EventArgs e)
            {
                Test();
            }        private void Test()
            {
                Type type = Type.GetType("TestStatic.A");
                MethodInfo mi = type.GetMethod("Test");
                object o = mi.Invoke(null, new object[] { "123" });
            }
        }
        public class A
        {
            public static string Test(string a)
            {
                Console.WriteLine("A.Test() is run;"+a);
                return a;
            }
        }
    }
      

  29.   

    个人觉得,你应该参考一下provider模式,能够满足你的要求,并且代码也非常漂亮.
      

  30.   

    下面是对指定类的属性读写值的方法,修改一下应该可以。把myType.GetField改成myType.GetMethod,看看帮助。 public bool SetControlValue(object ClassInstance, string ControlName, object Value)
    {   //直接对 _country_id 写值,不引发 country_id 的 Set 函数。
    Type myType = ClassInstance.GetType();
    FieldInfo myFieldInfo = myType.GetField(ControlName,BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance);
       
    if(myFieldInfo != null)
    {   
    try   
    {   
    myFieldInfo.SetValue(ClassInstance, Value);
    object asdf = myFieldInfo.GetValue(ClassInstance); //这是读取值的方法,不引发 get
    return true;
    }   
    catch //(Exception e)
    {   
    //MessageBox.Show(e.Message);
    }   
    }
    return false;
    }
      

  31.   

    private void InvokeMdiChildMethod(string MothodName)
            {
                if (this.ActiveMdiChild == null)
                    return;            Type t = ActiveMdiChild.GetType();
                Assembly assembly = Assembly.GetAssembly(t);
                MethodInfo method = t.GetMethod(MothodName, BindingFlags.Public | BindingFlags.NonPublic
                    | BindingFlags.Instance | BindingFlags.Static);            if (method == null)
                    return;            t.InvokeMember(MothodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic
                    | BindingFlags.Instance | BindingFlags.Static, null, ActiveMdiChild, null);
            }
      

  32.   

    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Test("A");
            //Test("B");
        }    private void Test(string ClassName)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            Type type = assembly.GetType(ClassName);
            string result = (string)type.InvokeMember("Test",BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, null);
            Response.Write(result);
        }
    }public class A
    {
        public static string Test()
        {
            return "Call Class A";
        }
    }public class B
    {
        public static string Test()
        {
            return "Call Class B";
        }
    }
      

  33.   

    楼上的兄弟真厉害,理解我的意思了。
    可是,你的代码能编译成功,并不能运行成功!不知你是否有测试过才发上来的?出错原因:未将对象引用设置到对象的实例。出错的代码是:string result = (string)type.InvokeMember("Test", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, null);
    行 25:         Response.Write(result);
    行 26:     }
      

  34.   

    wwy830916(问题多如牛毛) ,这位兄弟的代码全部写在 default.aspx一个页面时,是能正常运行的。但是,我的类全部是写在App_Code文件夹中的,引用总是失败!因为项目的类有上百个,每个类约有一百来行代码,总不能写到一个文件里吧?那就像是在看长篇小说了。
      

  35.   

    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            this.InvokeMethod("Class1", "WriteString", null);
            this.InvokeMethod("Class2", "WriteString", new object[] { "AAAAAA"});
        }    private void InvokeMethod(string className, string methodName,object[] paras)
        {
            string tmp = typeof(Class1).AssemblyQualifiedName;
            tmp = tmp.Substring(tmp.IndexOf(","));
            Type t = Type.GetType(className + tmp);
            t.InvokeMember(methodName, BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public|BindingFlags.NonPublic, null, null, paras);
        }
    }public class Class1
    {
        private static void WriteString()
        {
            System.Web.HttpContext.Current.Response.Write("This is Class1");
        }
    }
    public class Class2
    {
        public static void WriteString(string s)
        {
            System.Web.HttpContext.Current.Response.Write("This is Class2: "+s);
        }
    }
      

  36.   

    using System.Reflection;        string className = "Class1";
            string methodName = "Test";        Assembly a = Assembly.Load("App_Code");
            Type t = a.GetType(className);
            MethodInfo mi = t.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
            if (mi != null)
                mi.Invoke(null,null);