c# - 有一个只有属性的基本接口是错误的吗?
问题描述
我正在尝试构建一个灵活的结构,它可以返回任何类型的对象(特定于每个客户端 REST/WCF 集成),我想知道返回它的最佳方式是什么。
我的想法是拥有一个带有一个属性的基本接口,该属性将由返回类型继承,并且我想让它尽可能通用。
所以:
public interface IBase
{
string Id { get;set; }
}
public class ReturnType : IBase
{
public string Id { get; set; }
public string PropertyOne { get; set; }
public string PropertyTwo { get; set; }
}
public IBase Call()
{
return (IBase)ServiceCall();
}
public object ServiceCall()
{
return new ReturnType();
}
编辑:
为了给出更好的主意,这是我正在处理的当前流程:
步骤1
public ISwitchResponse CompanySwitch(AddSwitchRequest switchRequest)
{
return GetCalculator(CreditBrokerCalculatorNames.MortgageLoan).Switch<UCISwitchResponse>(switchRequest);
}
private ICreditBrokerOfferCalculationService GetCalculator(CreditBrokerCalculatorNames calculatorName)
{
return _calculatorResolver.CreateCreditBrokerSwitchCalculator(calculatorName.ToString());
}
第2步
public T Switch<T>(AddSwitchRequest request) where T : ISwitchResponse
{
SwitchRequest switchRequest = _calculatorRepository.AddAndGetSwitchRequest(request.RequestId, request.ServiceOfferId, request.SwitchAnswers, request.HasFullALineAccess, request.IsDecoAssociated);
var response = (T)_companyIntegratorManager.CommunicateNewSwitch(switchRequest);
response.HumanId = _calculatorRepository.GetCalculationInstanceHumanId(request.RequestId);
return response;
}
第 3 步
public object CommunicateNewSwitch(SwitchRequest switchRequest)
{
var switchAnswers = switchRequest.SwitchAdditionalAnswers.ToDictionary(_ => _.PropertyName, _ => _.PropertyValue,
StringComparer.InvariantCultureIgnoreCase);
Provider provider = switchRequest.ServiceOffer.Provider;
string serviceName = $"{provider.CommunicatorPrefix.Value}{provider.Calculator.Name}";
ICompanyService service = GetCreditCompanyServiceInstance(serviceName);
try
{
var switchResponse = service.Switch(switchAnswers);
return switchResponse;
}
catch (Exception ex)
{
_logger.Error($"CommunicateNewSwitch - ERROR! UCI MakeSwitch {switchRequest.CalculationInstanceId} threw exception.", ex);
throw new Exception($"CommunicateNewSwitch - ERROR! UCI MakeSwitch {switchRequest.CalculationInstanceId} threw exception.", ex);
}
}
第4步
public object Switch(Dictionary<string, string> answers)
{
var factory = new DictionaryAdapterFactory();
var request = factory.GetAdapter<IUCISwitchRequest>(answers);
using (var client = new HttpClient { BaseAddress = new Uri(_url) })
{
try
{
string json = JsonConvert.SerializeObject(request);
string auth = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_username}:{_pwd}"));
var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
HttpResponseMessage response = client.PostAsync("prequalificar", stringContent).Result;
UCISwitchResponse result = JsonConvert.DeserializeObject<UCISwitchResponse>(response.Content.ReadAsStringAsync().Result);
return result;
}
catch (Exception ex)
{
_logger.Error($"Switch - ERROR! UCI Switch threw exception.", ex);
throw new Exception($"MakeSwitch - ERROR! UCI MakeSwitch threw exception.", ex);
}
}
}
界面
public interface ISwitchResponse
{
[DataMember]
string HumanId { get; set; }
}
班级
public class UCISwitchResponse : ISwitchResponse
{
public string HumanId { get; set; }
[DataMember]
[JsonProperty(PropertyName = "Resultado")]
public string Result { get; set; }
[DataMember]
[JsonProperty(PropertyName = "LeadID")]
public string LeadId { get; set; }
[DataMember]
[JsonProperty(PropertyName = "Pdf")]
public string PdfUrl { get; set; }
[DataMember]
[JsonProperty(PropertyName = "Motivo")]
public string Reason { get; set; }
[DataMember]
[JsonProperty(PropertyName = "Mensagem")]
public string Message { get; set; }
[DataMember]
[JsonProperty(PropertyName = "Erros")]
public List<Errors> Errors { get; set; }
}
public class Errors
{
[DataMember]
[JsonProperty(PropertyName = "Codigo")]
public int Code { get; set; }
[DataMember]
[JsonProperty(PropertyName = "Descricao")]
public string Description { get; set; }
}
我的问题是:这样做有错吗?我最好使用抽象类吗?如果没有,实现这一目标的最佳选择是什么?
解决方案
我想要的是调用一个 WCF 服务,它将与其他服务(WCF 或 REST)通信,并返回一个公共类型,我打算稍后在接收此接口的网站部分将其转换为特定类型。
public IBase Call() { return (IBase)ServiceCall(); } public object ServiceCall() { return new ReturnType(); }
这样做有错吗?
是的。
拥有一个只包含一个或几个属性的接口并没有错,但只有在调用者可以对这些属性做任何需要做的事情时,它才可用。
当你声明一个返回接口的方法时,你提供了一个契约,这意味着调用者不应该关心返回的实际类型。当方法返回 时ICollection<string>
,调用者不应将结果转换为列表、数组、集合或其他任何内容,因为这无法保证。可以保证的是,任何实现所述接口的类型都可以返回,这对于调用者来说应该足够了。
我相信你有你这样做的理由,比如抽象(隐藏肮脏的 Web 服务部分)或减少代码重复,但这不是方法。
如果您的调用者需要 a Foo
,则为他们提供返回 a 的方法Foo
。即使这Foo
恰好实现IBase
了,因为调用者不能对 an 做任何事情,IBase
他们必须将它强制转换为 a Foo
,一旦有人开始返回 a ,它就会中断Bar
。它会编译并运行 find 只要Bar : IBase
,但它会在演员阵容中爆炸。
所以你可能追求的是泛型,正如@vhr 所说:
var result = svc1.Call<ReturnType1>();
现在result
是调用代码可以做某事的类型。
推荐阅读
- python - 使用 pip 卸载具有依赖项的软件包
- quote - VBX 转义多个双引号
- opencv - jupyter notebook 中的 OpenCV 和 cv2 问题
- laravel - Laravel 表单请求更新时的唯一字段验证
- python - 如何从另一个函数访问嵌套函数内的变量?
- json - 如何将值解组为 map[string][int] 类型的 json 结构
- sql - 如何自动从 SQL 查询中的字段中提取内容?
- angular - 使用 NgRx 调用 API?
- solidity - ERC721:转接呼叫者既不是所有者也不是批准的
- amazon-s3 - 将 k8s 命名空间添加到 S3 存储桶路径