实现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>();
}
}
请建议。
声明一个所有类都将实现的接口,如
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();
}
}
所以,经验法则是:
如果你知道在编译时你想要使用的服务的接口,使用一个泛型工厂(即
Locator.GetService<ICanDoSomething>()
)。如果多个服务共享完全相同的接口,并且您需要在运行时区分它们,请使用带有类型参数的工厂(即
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框架。