【问题标题】:Calling static function via classname as a string in c#通过类名调用静态函数作为c#中的字符串
【发布时间】:2012-08-21 17:12:56
【问题描述】:

我的问题

我有一个我无法解决的问题。我不想使用这么多代码,因为我有多个扩展另一个类的类(在我的例子中它称为“数据”)。

我有一个日志文件,其中每个数据组都以特定的组名开头,例如“MitarbeiterSet”。抽象的 Data-Class 用于处理大量代码,我在其中实现了 "String[] data" 之类的变量(用于从日志文件中解析的数据,例如 ) 或 "static String parseInduction",用于确定该类是否适合从中创建对象。

我有另一个类,称为 ParseMonitor,它创建 StreamReader 来解析日志文件。因此,如果找到正确的类,我会从正确的类中引入 setDataArray(StreamReader sr) 函数来解析数据数组。 (此时我必须告诉你,我需要那些不同的类,因为我需要专门将它们上传到 sql server。)

这个静态函数自己创建一个对象,并使用 parseLine(String line) 函数用给定行的数据填充对象。

我需要什么。

我想调用任何类的静态函数,只要有这个类的名字。所以我不必使用那么多代码并且能够添加更多类。

稍后我想调用每个类并使用 uploadToServer() 将其上传到服务器。

这可能吗?

【问题讨论】:

    标签: c# string function reflection static


    【解决方案1】:

    由于您的静态方法无论如何都在创建其类的实例,因此我建议采用不同的方法:

    创建一个所有包含ParseLine的类都可以实现的接口。 (把返回类型改成正确的):

    public interface IParseLine
    {
        string ParseLine(string line);
    }
    

    让所有包含ParseLine() 的类都实现IParseLine

    创建该类的一个实例,将其转换为IParseLine,然后执行该方法:

    IParseLine pl = Activator.CreateInstance(Type.GetType(className)) as IParseLine;
    if (pl != null)
    {
        string parsedString = pl.ParseLine(line);
        // ...
    }
    

    编辑来自 cmets:

    我想创建一个while循环,可以这样表述: while{!sr.EndofStream){ line = sr.ReadLine(); for(int i = 0; i

    我没有对此进行测试,但是您可以将代码更改为类似这样(缓存获取MYINDICATOR所需的反射):

    IList<KeyValuePair<string, Type>> typeIndicators = classNames.Select(x => {
        Type t = Type.GetType(x);
        string indicator = (string)t.GetField("MYINDICATOR", BindingFlags.Public | BindingFlags.Static).GetValue(null);
        return new KeyValuePair(indicator, t);
    });
    
    while (!sr.EndOfStream)
    {
        line = sr.ReadLine();
        foreach (var types in typeIndicators)
        {
            if (line.Contains(types.Key))
            {
                 IParseLine pl = Activator.CreateInstance(types.Value) as IParseLine;
                 if (pl != null)
                 {
                     string parsedString = pl.ParseLine(line);
                 }
            }
        }
    }
    

    【讨论】:

    • 我想创建一个while循环,可以这样表述:while{!sr.EndofStream){ line = sr.ReadLine(); for(int i = 0; i &lt; classNames.length; i++){ if(line.Contains(classNames[i].MYINDICATOR){ CALL classNames[i] STATIC METHOD TO PARSE THE FOLLOWING LINES AND CREATE DATA Objects of its Class } }
    • 没有理由不能将它放入循环或辅助函数或其他任何东西中。
    • 我不得不编辑很多,抱歉。重要的是要声明,我需要这个 MYINDICATOR 东西。另一个想法是创建每个类的第一个对象并使用这个对象来获取 MYINDICATOR 变量并创建和保存以下对象。但我认为这可能是“棘手”的方式
    • 您需要对类进行反思以获得常量MYINDICATOR。我添加了一个扩展示例来说明。
    【解决方案2】:

    我想调用任何类的静态函数,只要有这个类的名字。

    好吧,您可以使用Type.GetType(className) 来获取Type(请注意,名称至少需要完全限定,包括命名空间,并且根据您的具体情况可能还需要程序集名称),然后是@987654322 @获取MethodInfo。最后调用MethodBase.Invoke调用该方法。

    如果您可以使用typeof(Foo) 而不是使用字符串,这将使代码更简单、更健壮。

    (旁注:如果您的方法真的被称为 parseLineparseInductionsetDataArray 等,您应该考虑重命名它们以遵循 .NET 命名约定 :)

    【讨论】:

    • 我来自 Java,所以这对我来说真的很难理解 - 哈哈
    • @DominikVogt:相当于Class.forNameClass.getDeclaredMethodMethod.invoke。但我强烈建议您停止使用 Java 惯用语,而采用 C# 惯用语——尤其是命名约定 :)
    • 我会坚持下去 :) Type myType = Type.GetType("DienstGruppe"); MethodInfo info = myType.GetMethod("setDataArray"); info.Invoke(sr); 我不明白我的错误。你看到我的错误了吗?我收到 CS1501 错误,但不知道原因。我认为这可能与命名空间有关。我与我的类在同一个命名空间中,但我想调用该函数。
    • @DominikVogt:CS1501 听起来像是一个编译时错误。我没有记住那些编译器代码——但它应该给你足够的信息告诉你问题出在哪一行。我怀疑你实际上想要info.Invoke(null, new object[] { sr })
    • 我认为这对我有帮助 link 不过谢谢
    【解决方案3】:

    我想我知道你来自哪里。在下面这个简单的例子中,我有一个带有方法的静态类(这没什么好奇怪的)。

    public static class MyStaticClass
    {
        public static DateTime GetTime()
        {
            return DateTime.Now;
        }
    }
    

    如果我想使用反射调用该方法,我可以使用以下代码,但它确实假设 MyStaticClass 类可通过引用或在同一项目等中使用。

    MethodInfo method = typeof(MyStaticClass).GetMethod("GetTime");
    object result = method.Invoke(null, null);
    
    if (result is DateTime)
    {
        Console.WriteLine(((DateTime)result).ToLongTimeString());
    }
    

    当你没有对类的引用时,你似乎不想要的是一种这样做的方法。在这种情况下,请尝试以下操作:

    MethodInfo method = Type.GetType("PocStaticReflect.MyStaticClass, PocStaticReflect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null").GetMethod("GetTime");
    object result = method.Invoke(null, null);
    
    if (result is DateTime)
    {
        Console.WriteLine(((DateTime)result).ToLongTimeString());
    }
    

    注意完全限定的类名!

    如果你得到这个工作,那么你可以简单地循环你的类名并调用你想要的方法。显然,您可能希望在 GetMethod() 调用中进行更多的错误检查和更多的细节,但是这将为您提供它的要点。在遍历文件夹中的程序集以获取应用程序的插件之前,我已经做了类似的事情。那个时候,每个类都实现了一个接口,使它们更容易定位,这可能是一个有用的路径。

    【讨论】:

      【解决方案4】:

      或者试试这个:

       private static object GetResultFromStaticMethodClass(string qualifiedClassName, string method)
       {
            Type StaticClass = Type.GetType(qualifiedClassName);
            MethodInfo methodInfo = StaticClass.GetMethod(method);
            object result = methodInfo.Invoke(null, null);
            return result;
       }
      

      用途:

      object result = GetResultFromStaticMethodClass(
          "Utilities.StringHelper,DaProject",
          "ToList"
      );
      

      这会调用 StringHelper 类、Utilities 命名空间、DaProject 中的静态方法 ToList项目(相同的程序集和项目名称)。

      如果需要参数,在methodInfo.Invoke(null, null)调用的第二个参数中添加

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 2016-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多