C# 当方法代码相似但调用方名称发生变化时,使用什么方法?
我正在设计一个类,它只是包装了另一个类库中的几个方法调用 下面是我的班级的样子:C# 当方法代码相似但调用方名称发生变化时,使用什么方法?,c#,.net,.net-standard,C#,.net,.net Standard,我正在设计一个类,它只是包装了另一个类库中的几个方法调用 下面是我的班级的样子: public class MyClass { IService Service; //Third Party Library. public MyClass() { // Initialization } public string MethodA() { Service.MethodA(); return Serv
public class MyClass
{
IService Service; //Third Party Library.
public MyClass()
{
// Initialization
}
public string MethodA()
{
Service.MethodA();
return Service.GetResult();
}
public string MethodB()
{
Service.MethodB();
return Service.GetResult();
}
public string MethodC()
{
Service.MethodC();
return Service.GetResult();
}
public string MethodD()
{
Service.MethodD();
return Service.GetResult();
}
}
在反射的帮助下,我对上述代码进行了一定程度的重构,如下所示:
public class MyClass
{
IService Service;
public MyClass()
{
// Initialization
}
public string MethodA()
{
return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
}
public string MethodB()
{
return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
}
public string MethodC()
{
return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
}
public string MethodD()
{
return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
}
private string GetResult(string methodName)
{
Service.GetType().GetMethods().FirstOrDefault(x => x.Name == methodName).Invoke(Service, null);
return Service.GetResult();
}
}
我看到的一个缺点是,假设正在使用的库将来发布新版本,并且如果方法名称中有任何更改,它不会给出任何编译错误,因为我正在使用反射,但在运行时,它会抛出异常
有没有更好的替代方案
另外,有没有什么方法可以在有/无反射的情况下进一步优化代码?我会使用您提供的两个选项中的任何一个,并添加单元测试,以验证用于该特定构建的第三方库的版本是否仍然具有这些方法。实际上,您可以使用一些反射并深入进行那些单元测试,例如,检查方法签名是否相同等等。这些单元测试将保证,如果第三方库中的方法发生更改,您的构建将失败 一旦构建通过了(以及所有的单元测试),就不必担心它的剩余生命周期 p.S.反射一般都很慢。如果选择第二个选项,您可能希望在实现它之前在第一个选项和第二个选项之间进行性能比较。拥有这些单元测试意味着不需要使用第二个选项
p.S.2.我本想写一篇评论而不是帖子,但我没有足够的声誉你可以将反映的
MethodInfo
缓存到字典中
,这样你就不必每次调用MyClass.GetResult(string methodName)
当然,如果您的第三方依赖项更改了一个方法的名称,那么您仍然会遇到一个问题,即它将自身显示为运行时错误而不是编译时错误。因此,您可以通过使用nameof
和IService
上的方法名来解决这个问题
public class MyClass
{
public string MethodA()
{
return GetResult(nameof(IService.MethodA));
}
}
现在,如果IService
上的方法名称发生更改,则会出现编译器错误
这应该比您的示例在性能方面得到更好的优化。除了在这一点上你得到了什么?MyClass
上的每个公共方法仍然必须直接引用它在iSeries
上的相应方法。也就是说,MyClass.MethodA
直接引用了IService.MethodA
。那么,为什么不直接调用Service.MethodA
来节省反射的复杂性和性能成本呢
此外,您还担心您的第三方依赖关系会更改方法名称,并且会创建运行时错误而不是编译时错误,这里概述的方法应该解决这一问题。但是,如果您的第三方依赖项更改了方法的签名怎么办?例如,IService.MethodA()
变为IService.MethodA(字符串参数1)
?现在您又回到了原点,出现了运行时异常,而不是编译器错误
我知道你所发布的只是一个例子,我不能完全理解你仅仅基于一个例子所要做的事情。但是,基于这个例子,在我看来,
MyClass
的最佳版本是没有反射的版本。我真的很难看到通过使用反射来调用IService
,而不是直接调用方法,可以获得什么好处。您可以在编译时使用T4模板之类的东西生成代码。作为奖励,这避免了在运行时进行反射的成本。@jeroenmoster,甚至在构建时使用time@JeroenMostert在T4模板中,仅用于Web。我正在尝试使用.Net标准为控制台应用程序实现这一点。不,T4不仅仅适用于web项目。它适用于VS将在中运行自定义工具的任何项目,包括.NET标准项目(在早期版本中,T4没有.NET核心支持,但这已经实现)。根据phuzi的说法,源代码生成器也是热门的新事物,尽管这可能需要工具升级(功能本身还不是最终的)。T4模板只是生成C代码的C代码。它可以在编译时加载库类,反映IService
的方法,并生成一个MyClass
来精确封装这些方法。如果库发生更改,生成的代码也会随之更改,如果其他代码依赖于这些方法中的任何一种,则会出现编译错误。如果您想确保在已部署的应用程序中将库替换为二进制文件(即,不重新编译)时不会出现问题,则这是另一回事,但运行时错误当然是不可避免的(除非您求助于动态
)。谢谢,但除了编译/运行时错误,我所期待的是一些代码优化以及上述解决方案,如果有的话。如何使用字典?类似于:MyClass.MethodD=>Execute(CurrentMethodName),感谢您的建议。-><代码>为什么不直接呼叫服务。MethodA并为自己节省反射的复杂性和性能成本——事实上,正如您所看到的,在所有方法中有两个几乎相同的代码行,在第1行,唯一的变化是方法名称,所以我认为这可能是一种代码味道,有没有更好的方法来优化它?我缓存了所有的方法,当我在有/没有反射的情况下执行代码时,性能几乎相同。那么,使用Service.MethodA
而不是反射并在每个方法中保留重复行是否更好?这就是我要做的。例如,只需在MyClass.MethodA
中调用Service.MethodA
和Service.GetResult
,并在MyClass
的其余部分遵循该模式即可。就像你在纽约一样
public class MyClass
{
public string MethodA()
{
return GetResult(nameof(MethodA));
}
}
public class MyClass
{
public string MethodA()
{
return GetResult(nameof(IService.MethodA));
}
}