C# 如何调用在运行时选择的几个静态类之一的方法?

C# 如何调用在运行时选择的几个静态类之一的方法?,c#,reflection,static-methods,C#,Reflection,Static Methods,我使用几个类来提供服务,例如,有一个类用于FTP,另一个类用于HTTP,这两个类都实现了相同的方法,但都是根据协议定制的: public static class FtpProvider { public static string GetString () { return "1"; } } public static class HttpProvider { public static string GetString () { return "2";

我使用几个类来提供服务,例如,有一个类用于FTP,另一个类用于HTTP,这两个类都实现了相同的方法,但都是根据协议定制的:

public static class FtpProvider { public static string GetString () { return "1"; } }
public static class HttpProvider { public static string GetString () { return "2"; } }
我需要一个简单的服务选择器来切换提供服务的静态类。我使用类型变量来保存当前提供程序,例如

Type _type = (condition) ? typeof (FtpProvider) : typeof (HttpProvider);
然后,我使用反射调用所选类的方法。整个代码:

class Program {
    static void Main () {
        Type _type = (new Random ().NextDouble () > .5) ? typeof (FtpProvider) : typeof (HttpProvider);
        string _methodName = nameof (FtpProvider.GetString);
        MethodInfo _method = _type.GetMethod (
            _methodName,
            BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
        object _result = _method.Invoke (null, null);
        Console.WriteLine (_result.ToString ()); Console.ReadKey ();
    }
}
public static class FtpProvider { public static string GetString () { return "1"; } }
public static class HttpProvider { public static string GetString () { return "2"; } }
这确实有效,但在运行时切换静态类型时,这确实是一段难看的代码,因为它只是用来替换像
currentProvider.GetString()
这样的调用。所以我想知道:

  • 如果有更好的切换静态类提供程序的设计
  • 如果这种方式可以接受,代码可以简化吗
更新:

  • 我尝试了带有接口的单例模式,但静态方法无法实现接口,而且实例创建对我来说太多了,因为服务是无状态的。我还尝试了抽象基类,但构造函数必须在每个派生类中

  • 如果静态方法是一个问题,请解释原因(我理解它确实不是面向对象的)


  • 静态类型不支持继承或Liskov替换。他们不是故意的。这就是你的代码如此混乱的原因——你所做的事情非常奇怪。如果您想让这些提供程序变得简单,那么应该将它们实现为具有公共接口的常规实例类

    这就是说,如果您完全无法使用静态类,那么使用提供者映射是一种更容易的方法

    var map = new Dictionary<string,Func<string>>
    {
        { "HTTP", HttpProvider.GetString },
        { "FTP", FtpProvider.GetString }
    };
    

    下面是一个使用单例模式而不是
    静态类的示例,以及一个实现所需功能的接口。不需要思考。您可以从静态
    CurrentProvider
    属性访问“provider”(或者根据自己的喜好更改访问权限)

    希望您的提供程序类重叠足够多,以便有一个公共接口可以与它们一起使用。然后,你的应用程序的其余部分就不必知道实际的提供商类型;它们只是与界面交互

    注意,我已经为singleton
    private
    创建了默认构造函数,因此获取此类实例的唯一方法是调用static instance属性。因此,它们的行为类似于静态类。(如果您真的不希望人们在静态实例属性之外构造它们,您也可以考虑标记这些代码>密封< /代码>)

    您仍然可以通过切换条件变量来切换提供程序。我建议不要使用
    bool
    ,而是使用
    enum
    ,不过您可以在以后修改条件的工作方式

    using System;
    
    namespace SomeNamespace
    {
        public class Program
        {
            static void Main()
            {
                Condition = new Random().NextDouble() > .5;
                Console.WriteLine(CurrentProvider.GetString()); Console.ReadKey();
            }
    
            static bool Condition;
            static IProvider CurrentProvider => Condition ? FtpProvider.Instance as IProvider : HttpProvider.Instance as IProvider;
        }
    
        // interface allows for multiple provider types
        public interface IProvider
        {
            string GetString();
        }
        public class FtpProvider : IProvider
        {
            // use Lazy<T> to implement Singleton pattern
            private static readonly Lazy<FtpProvider> lazy = new Lazy<FtpProvider>(() => new FtpProvider());
            public static FtpProvider Instance
            {
                get
                {
                    return lazy.Value;
                }
            }
            // don't allow normal construction of this class
            // force everyone to use Instance
            private FtpProvider() { }
    
            public string GetString() => "1"; 
        }
        public class HttpProvider : IProvider
        {
            // use Lazy<T> to implement Singleton pattern
            private static readonly Lazy<HttpProvider> lazy = new Lazy<HttpProvider>(() => new HttpProvider());
            public static HttpProvider Instance
            {
                get
                {
                    return lazy.Value;
                }
            }
            // don't allow normal construction of this class
            // force everyone to use Instance
            private HttpProvider() { }
    
            public string GetString() => "2";
        }
    }
    
    使用系统;
    名称空间名称空间
    {
    公共课程
    {
    静态void Main()
    {
    条件=new Random().NextDouble()>.5;
    Console.WriteLine(CurrentProvider.GetString());Console.ReadKey();
    }
    静态布尔条件;
    静态IProvider CurrentProvider=>条件?FtpProvider.Instance作为IProvider:HttpProvider.Instance作为IProvider;
    }
    //接口允许多种提供程序类型
    公共接口IProvider
    {
    字符串GetString();
    }
    公共类FtpProvider:IProvider
    {
    //使用Lazy实现单例模式
    private static readonly Lazy Lazy=new Lazy(()=>new FtpProvider());
    公共静态FtpProvider实例
    {
    收到
    {
    返回lazy.Value;
    }
    }
    //不允许该类的正常构造
    //强制所有人使用实例
    私有FtpProvider(){}
    公共字符串GetString()=>“1”;
    }
    公共类HttpProvider:IProvider
    {
    //使用Lazy实现单例模式
    private static readonly Lazy Lazy=new Lazy(()=>new HttpProvider());
    公共静态HttpProvider实例
    {
    收到
    {
    返回lazy.Value;
    }
    }
    //不允许该类的正常构造
    //强制所有人使用实例
    私有HttpProvider(){}
    公共字符串GetString()=>“2”;
    }
    }
    
    为什么这些类必须是静态的?您可以使用一个接口来包含
    GetString
    方法,并让两个类实现相同的接口。然后,其他一些代码可以选择要实例化和使用的类类型,但它会作为接口类型传递。如果希望每个提供程序类型只有一个实例,那么可以使用Singleton模式。好的,这很有趣,我需要每个服务有一个映射,可能超过20个,但这是一个很好的重新启动,谢谢。好的,我尝试了一下,发现了两个简单的问题:实例创建和无法使用静态方法实现接口。我必须说,没有是不可能的。如果实例创建是一个问题,那么您可能需要更新您的问题,提供更多关于为什么必须使所有内容都是静态的信息。是不是因为您无法控制静态类,比如说因为它们在编译库中?
    using System;
    
    namespace SomeNamespace
    {
        public class Program
        {
            static void Main()
            {
                Condition = new Random().NextDouble() > .5;
                Console.WriteLine(CurrentProvider.GetString()); Console.ReadKey();
            }
    
            static bool Condition;
            static IProvider CurrentProvider => Condition ? FtpProvider.Instance as IProvider : HttpProvider.Instance as IProvider;
        }
    
        // interface allows for multiple provider types
        public interface IProvider
        {
            string GetString();
        }
        public class FtpProvider : IProvider
        {
            // use Lazy<T> to implement Singleton pattern
            private static readonly Lazy<FtpProvider> lazy = new Lazy<FtpProvider>(() => new FtpProvider());
            public static FtpProvider Instance
            {
                get
                {
                    return lazy.Value;
                }
            }
            // don't allow normal construction of this class
            // force everyone to use Instance
            private FtpProvider() { }
    
            public string GetString() => "1"; 
        }
        public class HttpProvider : IProvider
        {
            // use Lazy<T> to implement Singleton pattern
            private static readonly Lazy<HttpProvider> lazy = new Lazy<HttpProvider>(() => new HttpProvider());
            public static HttpProvider Instance
            {
                get
                {
                    return lazy.Value;
                }
            }
            // don't allow normal construction of this class
            // force everyone to use Instance
            private HttpProvider() { }
    
            public string GetString() => "2";
        }
    }