首页 > 解决方案 > 有一个只有属性的基本接口是错误的吗?

问题描述

我正在尝试构建一个灵活的结构,它可以返回任何类型的对象(特定于每个客户端 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; }
}

我的问题是:这样做有错吗?我最好使用抽象类吗?如果没有,实现这一目标的最佳选择是什么?

标签: c#asp.netgenericsinterface

解决方案


我想要的是调用一个 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是调用代码可以做某事的类型。


推荐阅读