如何避免使用第三方Web服务重复代码-而无需使用动态代码? [英] How to avoid code repetition using a 3rd party web service - without using dynamic?
问题描述
我正在使用第三方网络服务,其中所有方法均具有以下签名:
I'm using a 3rd party web service where all it's methods have the following signature:
SomeResponseClass SomeMethod(SomeRequestClass request)
每个方法都有它自己的请求类和自己的响应类,但是还有一些事情所有请求都具有共同点,所有响应都具有共同点。
Every method has it's own request class and it's own response class, However there are a few things that all requests have in common, and all responses have in common.
每个请求类都有几个可识别的属性:用户名
和令牌
,每个响应类都有几个属性来指示是否存在错误: status
和错误
。
Every request class has a couple of properties for identification: username
and token
, and every response class have a couple of properties to indicate if there was an error: status
and error
.
我正在寻找一种优雅的方法来创建一个实例化我的请求的方法-这样我就不必在调用该服务的每种方法中都重复自己。由于我无法更改类,并且所有类都没有通用的接口或基类,因此我发现的唯一解决方案是使用 dynamic
:
I'm looking for an elegant way to create a method that will instantiate my requests - so that I will not have to repeat myself in every method calling the service. Since I can't change the classes, and there is no common interface or base class to all of them, the only solution I found was to use dynamic
:
private T CreateRequest<T>() where T : new()
{
if(string.IsNullOrEmpty(_Token))
{
Login();
}
// this has to be dynamic for the next 2 rows to pass compilation.
dynamic request = new T();
request.username = _UserName;
request.token = _Token;
return (T)request;
}
类似于从服务响应中填充我自己的实体的内容:
And something similar to populate my own entities from the service responses:
// response have to be dynamic for getting the error and status properties
private static T CreateServiceResponse<T>(dynamic response) where T : ServiceResponse, new()
{
T result = new T();
result.Error = (response == null) ? "Service response is null" : response.error;
result.Status = (response == null) ? -1 : response.status;
return result;
}
(此方法在我用来填充实体的每种方法中都使用(全部来自 ServiceResponse
)以及服务响应中的数据。)
(This method is used inside every method that I use to populate my entities (all derived from ServiceResponse
) with the data from the service response.)
有没有办法做类似的事情这不使用 dynamic
?
对我来说,感觉有点像是在使用肮脏的骇客...
Is there any way to do something like this without using dynamic
?
To me, it kinda feels like using a dirty hack...
如果我能以某种方式注入所有实施请求的通用接口,用于实现所有响应的通用接口,我可以使用简单的泛型,但是我想那是不可能的,还是这样?
If I could somehow "inject" a common interface for all requests to implement and a common interface for all responses to implement I could use simple Generics, but I guess that's impossible, or is it?
推荐答案
使用Visual Studio创建的服务引用时,所有生成的类都标记为 partial
。这意味着您可以使用自己的代码扩展它们。在您的情况下,这将是一个提供重复属性的接口。您可以将该接口用作一般约束。
When you are using service references created by visual studio, all generated classes are marked as partial
. That means you can extend them with your own code. In your case that would be an interface that provides the repetitive properties. You can use that interface as a generic constraint.
首先创建公共接口。为了使事情变得容易,您可以使用服务参考中定义的通用属性使用相同的名称和类型:
You first create the common interface. To make things easy, you use the same name and type for your common properties as defined in the service reference:
interface IRequest {
string username { get; set; }
string token { get; set; }
}
然后在与服务引用相同的名称空间中创建代码文件您可以为每个服务请求类定义一个局部类(具有相同的名称)。以下每个类均实现您的接口:
You then create a code file and in the same namespace as the service reference you define a partial class for each service request class (with the same name). Each of these classes implements your interface:
partial class SomeRequestClass : IRequest {}
选择相同的属性名称和类型,您不必专门实现该接口。
Having chosen the same property names and types, you don‘t have to specifically implement the interface.
最后,您使用通用约束:
Finally you use generic constraints:
private T CreateRequest<T>() where T : IRequest, new()
{
if(string.IsNullOrEmpty(_Token))
{
Login();
}
T request = new T();
request.username = _UserName;
request.token = _Token;
return request;
}
这篇关于如何避免使用第三方Web服务重复代码-而无需使用动态代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!