【问题标题】:Better approach to work with different types in a inherited class在继承类中处理不同类型的更好方法
【发布时间】:2023-04-05 03:25:01
【问题描述】:

我正在使用 N 个提供商发送 SMS 消息的 Web 服务。每个提供者在其自己的 Web 服务中接收不同格式的消息。

为了在我的 Web 服务中创建模式,我创建了一个抽象类,其中包含要为每个提供者实现的许多方法。

有些方法需要接收一个可以是不同类型的对象,这取决于继承它的子类(提供者)。其中一种方法返回一个对象,该对象至少可以是两种不同的类型。

我使用“object”关键字实现了这一点,它允许我传递或返回任何对象:

public abstract class Provider {
    protected HttpClient _Client;
    protected SMSManagerAPIContext _Context;

    public abstract DeliveryResponse SendSMS(object Sms);
    protected abstract DeliveryResponse ParseResponse(HttpResponseMessage Response);
    public abstract object PrepareMessage(SMS Sms);
    protected abstract void SaveResponse(object Sms, HttpResponseMessage Response);
}

SendSMS方法中接收到的对象SmsPrepareMessage方法的返回值。问题是PrepareMessage 可以返回不同类型的对象。

(例如,我的一个提供者接受发送一条或多条消息的请求,但每个消息的对象都不同。然后我在PrepareMessage 方法中返回正确的对象,SendSMS 方法发送它作为提供者的 JSON 对象。)

它可以工作,但在开发过程中会在子类中引起一些转换问题,我想知道是否有更好的方法来做到这一点。 我已经阅读了一些关于它的问题:

C# Return Different Types?

Generic method that can return different types

我认为使用泛型的重载方法会更好,但我没有使用 C# 的经验。

有什么想法吗?

【问题讨论】:

  • 你可以使用dynamic作为返回类型。
  • 嗯,它似乎工作正常!您知道使用泛型使用动态 x 在性能上是否存在一些差异吗?我希望它会被许多用户同时调用。
  • 您可以自己阅读stackoverflow.com/a/828401/6677992
  • 谢谢。 Gishu 的回答说:“性能:泛型将使用值类型的算法/代码的性能提高了一个显着的数量级。它阻止了整个装箱-拆箱周期,这让我们在使用前泛型时付出了代价。动态也没有为此做任何事情。 "

标签: c# inheritance return-type


【解决方案1】:

我认为你是对的,这听起来确实是一个使用泛型的好地方,也许像这样,其中“T”(按惯例称为 t)是你正在使用的类型。

public abstract class Provider<T>
{
    protected HttpClient _Client;
    protected SMSManagerAPIContext _Context;

    public abstract DeliveryResponse SendSMS(T Sms);
    protected abstract DeliveryResponse ParseResponse(HttpResponseMessage Response);
    public abstract T PrepareMessage(SMS Sms);
    protected abstract void SaveResponse(object Sms, HttpResponseMessage Response);
}


public class SMS {
    public string Message { get; set; }
}

public class SMSManagerAPIContext{}


public class DeliveryResponse { }


public class PremiumSMS
{
    public double Cost { get; set; }
    public string Message { get; set; }

}


public class PremiumSmsProvider : Provider<PremiumSMS>
{
    public const double Cost = 3.99;

    public override PremiumSMS PrepareMessage(SMS Sms)
    {
        return new PremiumSMS {
            Message = Sms.Message, 
            Cost = Cost
        };
    }

    public override DeliveryResponse SendSMS(PremiumSMS Sms)
    {
        throw new NotImplementedException();
    }

    protected override DeliveryResponse ParseResponse(HttpResponseMessage Response)
    {
        throw new NotImplementedException();
    }

    protected override void SaveResponse(object Sms, HttpResponseMessage Response)
    {
        throw new NotImplementedException();
    }
}

public class FreeSMS
{

    public string Message { get; set; }

}



public class FreeSmsProvider : Provider<FreeSMS>
{
    public override FreeSMS PrepareMessage(SMS Sms)
    {
        return new FreeSMS{
            Message = Sms.Message
        };
    }

    public override DeliveryResponse SendSMS(FreeSMS Sms)
    {
        throw new NotImplementedException();
    }

    protected override DeliveryResponse ParseResponse(HttpResponseMessage Response)
    {
        throw new NotImplementedException();
    }

    protected override void SaveResponse(object Sms, HttpResponseMessage Response)
    {
        throw new NotImplementedException();
    }
}

这里有更多关于泛型类的信息:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-classes

【讨论】:

  • 谢谢亚历克斯。但是有一种方法可以在 PrepareMessage 方法中返回第二个对象类型吗?我想使用相同的方法,但可以在方法内选择返回类型。有可能吗?
  • @CaioAmaral 如果使用这种技术,我已经添加了一个附加示例。或者,如果您希望共享部分代码,您可以使用泛型和继承(或组合)。
  • 我建议混合使用我的示例并重构代码以使用其他答案中建议的接口和工厂模式。
【解决方案2】:

使用工厂。使用这个的代码可能只关心给某个电话号码一个字符串消息,然后返回是否成功,如果不成功,可能会返回错误消息。

创建消息本身以遵循不同的提供者/实现应该只是在一个黑匣子中。不同的提供者只会有不同的构造函数。

public interface ISmsProvider 
{
    (bool, string) SendMessage(string number, string message);
}

public class SampleSmsProvider1 : ISmsProvider
{
    public SampleSmsProvider1(string userKey, string passKey) 
    {
        // initialize           
    }

    public (bool, string) SendMessage(string number, string message) 
    {
        // send the message (using a provider implementation from NuGet perhaps)

        // return success/fail and error message, if applicable
        return (true, string.Empty);
    }
}

public class SmsFactory
{
    public ISmsProvider GetProvider() 
    {
        // Initialize and return one of the ISmsProvider implementations, depending on (I guess) the configuration
    }
}

【讨论】:

  • 虽然这个答案并没有直接回答您关于处理不同返回类型的问题。我认为 pkr298 的回答解决了问题的症结所在,即您的班级的消费者可能只对发送消息感兴趣,而不是解决返回类型问题,而不是对消息的发送方式感兴趣,您应该可能想要重构以使用接口和工厂或提供者模式。来自我的 +1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
相关资源
最近更新 更多