实现c#中的泛型

本文关键字:泛型 实现 | 更新日期: 2023-09-27 18:07:08

我是一名学生,想在我的测试项目中实现通用。下面是我的代码

class clsCallService
{
    public void CallServiceMethod(string serviceName)
    {
        if (serviceName == "WEB")
            Web_Service.AddData("4G", DateTime.Now, DateTime.Now, "test");
        else if (serviceName == "VOICE")
            Voice_Service.AddData("4G", DateTime.Now, DateTime.Now, "test");
        else if (serviceName == "VIDEO")
            Video_Service.AddData("4G", DateTime.Now, DateTime.Now, "test");
    }
}       
class Web_Service
{
    public static void AddData(string technology, DateTime SDate, DateTime EDate, String someVariable)
    { 
        //Call DAL method
    }
}
class Voice_Service
{
    public static void AddData(string technology, DateTime SDate, DateTime EDate, String someVariable)
    {
        //Call DAL method
    }
}
class Video_Service
{
    public static void AddData(string technology, DateTime SDate, DateTime EDate, String someVariable)
    {
        //Call DAL method
    }
}

现在,我想创建一个泛型类。在这个类中,应该有一个泛型方法,它有一个泛型参数。所以,我不需要像上面那样写IF条件。我只需要传递一个对象的任何类和基的类型,方法将被调用。我想写一些代码,但不能这样做。

public class testGenericClass<T> where T : Web_Service, new()
{
    public void CallServiceMethod(string technology, DateTime SDate, DateTime EDate, String someVariable)
    {
        T.AddData(technology, SDate, EDate, someVariable);
    }
}

请建议。


得到一些有用的回复后更新——

更新代码

public class createGenericClass<T> where T : IWebService,IVoiceService
{
    public void CallDoSomeThing(T t, int x, int y)
    {
        t.DoSomeThing(x, y);
    }
    public void CallDoSomeThingElse(T t, int a, float b)
    {
        t.DoSomeThingElse(a, b);
    }
}
public interface IWebService
{
    void DoSomeThing(int x, int y);        
}
public interface IVoiceService
{
    void DoSomeThingElse(int a, float b);
}
public class Web_Service : IWebService
{
    public void DoSomeThing(int x, int y)
    { }    
}    
public class Voice_Service : IVoiceService
{
    public void DoSomeThingElse(int a, float b)
    { }
}

现在,我有两个不同的界面,即Web和Voice。两者都有不同的功能。我已经成功地实现了它,但我不能调用我的方法。我不知道怎么打电话。下面的代码(只是尝试创建一个新实例)

class Program
{
    static void Main(string[] args)
    {
        createGenericClass<IWebService> obj = new createGenericClass<IWebService>();
    }
}

请建议。

实现c#中的泛型

声明一个所有类都将实现的接口,如

interface IService 
{
    void AddData(string technology, DateTime SDate, DateTime EDate, String someVariable); 
}

然后每个类实现,如:

public class Web_Service : IService
{
    public void AddData(string technology, DateTime SDate, DateTime EDate, String someVariable) {
        // do stuff... 
    }
}
// etc...

我认为值得指出的是,如果您使用这样的接口,您可以接受类型为IService的参数,根本不需要泛型。

public void CallServiceMethod(IService service, string technology, DateTime SDate, DateTime EDate, String someVariable) 
{
    service.AddData(technology, SDate, EDate, someVariable); 
}

如果出于某种原因需要使用泛型方法,那么可以编写泛型方法,受接口约束,

public class testGenericClass<T> where T : IService
{
    public void CallServiceMethod(T t, string technology, DateTime SDate, DateTime EDate, String someVariable)
    {
        t.AddData(technology, SDate, EDate, someVariable);
    }
}

注意这个方法要求接口方法AddData()是一个实例方法,而不是像你现在这样的静态方法。

你不能在泛型类型上调用静态函数,所以我假设你正在尝试调用实例方法。您需要在调用.AddData(...)之前实例化T

public class testGenericClass<T> where T : Web_Service, new()
{
    public void CallServiceMethod(string technology, DateTime SDate, DateTime EDate, String someVariable)
    {
        new T().AddData(technology, SDate, EDate, someVariable);
    }
}
class Web_Service
{
    public void AddData(string technology, DateTime SDate, DateTime EDate, String someVariable)
    { 
        //Call DAL method
    }
}

当你查看。net基类库中泛型的使用情况时,你会发现它主要用于枚举和集合(例如List<T>IEnumerable<T>),即无论底层类型如何,数据结构的行为都是相同的。经验法则通常是:如果您需要检查泛型方法中确切的typeof(T),那么您可能做错了。

然而,在泛型方法中检查typeof(T)的一个原因是在工厂方法中,即:"服务定位器",它允许您获得特定类型的具体实例。这意味着你将有一个特殊的类,它在程序启动时注册各种接口的具体实现,这样你的程序就可以获得具体的依赖关系,而不知道它们是如何实例化的。

虽然纯粹的控制反转实际上是通过构造函数依赖注入实现的,但服务定位器方法提供了更好的设计,只需手动(使用new关键字)初始化依赖。但是,单元测试稍微困难一些,因为您的依赖项对于调用者来说仍然是不透明的。

考虑如下内容:

public interface IServiceLocator
{
    T GetService<T>();
}
// you use it whenever you would use `new` otherwise,
// to get a concrete instance of some interface, and
// you don't know and don't care where this instance 
// came from:
var webService = ServiceLocator.GetService<IWebService>();
var videoService = ServiceLocator.GetService<IVideoService>();

这个服务定位器可以是一个框架,或者你可以自己写,就像这样简单:

public class ServiceLocator : IServiceLocator
{
    readonly Dictionary<Type, Func<object>> _typeFactories =
        new Dictionary<Type, Func<object>>();
    public ServiceLocator()
    {
        // register a factory method for each service
        _typeFactories[typeof(IWebService)] = () => new SomeWebService();
        _typeFactories[typeof(IVideoService)] = () => new SomeVideoService();
        // services can also be singletons, if they can be shared
        _typeFactories[typeof(IVoiceService)] = () => VoiceService.Instance;
    }
    public T GetService<T>()
    {
        // get the factory method and invoke it
        // (you will probably want to have some checks here)
        var factory = _typeFactories[typeof(T)];
        return factory();
    }
}
然而,在您的例子中,似乎所有三个服务都共享一个公共接口,因此不需要泛型。您可能想这样使用它:

IDataService service = ServiceLocator.GetServiceByName("WEB");
service.AddData(...);

可以实现为:

public interface IDataService 
{
    void AddData(...);
}
public interface IServiceLocator
{
    IDataService GetServiceByName(string name);
}
public class ServiceLocator : IServiceLocator
{
    readonly Dictionary<string, Func<IDataService>> _typeFactories = 
        new Dictionary<string, Func<IDataService>>();
    public ServiceLocator()
    {
        _typeFactories["WEB"] = () => new SomeWebService();
        _typeFactories["VIDEO"] = () => new SomeVideoService();
        _typeFactories["VOICE"] = () => SomeVoiceService.Instance; // singleton            
    }
    public IDataService GetServiceByName(string name)
    {
        var factory = _typeFactories[name];
        return factory();
    }
}
所以,经验法则是:
  1. 如果你知道在编译时你想要使用的服务的接口,使用一个泛型工厂(即Locator.GetService<ICanDoSomething>())。

  2. 如果多个服务共享完全相同的接口,并且您需要在运行时区分它们,请使用带有类型参数的工厂(即Locator.GetServiceByName("some-service"))。

两种方法都不能保证该服务在运行时存在,但后者更容易出现运行时错误(输入错误的服务名称)。在弱耦合方面,这两种方法都不如纯DI,但比硬编码依赖项要好得多:

// bad
public SomeClassConstructor()
{
    _service = new WebService();
}
// better
public SomeClassConstructor(IServiceLocator serviceLocator)
{
    _service = serviceLocator.GetService<IWebService>();
}
// best
public SomeClassConstructor(IWebService webService)
{
    _service = webService;
}

我建议采用第三种方法。了解组合根,通常你甚至不需要一个花哨的DI框架。