C# - 通过相同的方法传递不同类型的对象

2024-01-10

原始问题

所以我有这 3 个对象......

public class obj1
{
  public int Id { get; set; }
  public string Name { get; set; }
}

public class obj2
{
  public int AccNum { get; set; }
  public string Name { get; set; }
}

public class obj3
{
  public string Email { get; set; }
  public string Phone { get; set; }
}

...以及一种应该接收其中之一的方法,在评估对象类型之后,程序应该决定调用哪个函数。

我尝试过使用泛型,但它没有按我的预期工作。到目前为止,这就是我所拥有的......

    public class NotificationHelper: INotificationHelper
    {

        public bool SendNotification<TNotInfo>(TNotInfo obj) where TNotInfo : class
        {
            if (contract.GetType() == typeof (obj1))
            {
                var sender = new SendSMS();
                return sender.Send(obj);
            }
            if (contract.GetType() == typeof(obj2))
            {
                var sender = new SendPush();
                return sender.Send(obj);
            }
            else
            {
                var sender = new SendEmail();
                return sender.Send(obj);
            }
        }
    }

但我收到错误“无法从 TNotInfo 转换为 Models.obj1”。有什么办法可以克服这个问题吗?或者我必须改变我的逻辑?

感谢任何帮助,提前致谢。

*Edit

using System;

namespace EmailNotifications
{

    public interface IEmailNotification
    {
        void SendEmailNotification();
    }

    public class EmailNotificationA : IEmailNotification
    {

        public void SendEmailNotification(Contract1 a)
        {
            Console.WriteLine($"Sending EmailNotificationA ({a})");
        }
    }

    public class EmailNotificationB : IEmailNotification
    {
        public void SendEmailNotification(Contract2 b)
        {
            Console.WriteLine($"Sending EmailNotificationB ({b})");
        }
    }

    public class EmailNotificationC : IEmailNotification
    {

        public void SendEmailNotification(Contrac3 c)
        {
            Console.WriteLine($"Sending EmailNotificationC ({c})");
        }
    }

    public class EmailNotificationService
    {
        private readonly IEmailNotification _emailNotification;

        public EmailNotificationService(IEmailNotification emailNotification)
        {
            this._emailNotification = emailNotification;
        }

        public void ServiceHelper()
        {
            _emailNotification.SendEmailNotification();
        }
    }
}

上述解决方案是我应用策略设计模式试图实现的目标。但我无法设法让我的接口方法接收不同的对象,这是必需的,因为每个通知都有自己的实现。正如上面的无工作示例所示,我对同一方法有 3 种不同的实现,它们都接收不同的对象。知道如何使这个逻辑发挥作用吗?


这就是界面设计的目的。首先定义一个通用接口:

public interface INotifier
{
    bool Notify();
}

其次,将其实施到您的objX课程:

public class obj1 : INotifier
{
    public int Id { get; set; }
    public string Name { get; set; }

    public bool Notify()
    {
        var sender = new SendSMS();
        return sender.Send(this);
    }
}

public class obj2 : INotifier
{
    public int AccNum { get; set; }
    public string Name { get; set; }

    public bool Notify()
    {
        var sender = new SendPush();
        return sender.Send(this);
    }
}

public class obj3 : INotifier
{
    public string Email { get; set; }
    public string Phone { get; set; }

    public bool Notify()
    {
        var sender = new SendEmail();
        return sender.Send(this);
    }
}

最后,更改通知方法以接受接口类型作为参数:

public class NotificationHelper : INotificationHelper
{
    public bool SendNotification(INotifier obj)
    {
        return obj.Notify();
    }
}

编辑(2019):

我正在重新审视这个答案,因为它似乎得到了相当多的关注。 OP 可能早已继续前进,但对于其他可能偶然发现这个答案的人来说,这是另一个解决方案。

我仍然相信接口是正确的出路。然而,上面建议的接口非常通用,最终并不是很有用。它还遇到了一些 DRY 违规,因为正如 Fabio 在评论中所说,如果两个objX类以相同的方式实现通知,这种方法迫使您在它们之间复制代码。

不是一个全局接口,而是为每个特定通知任务提供接口,即ISMSNotification, IPushNotification, IEmailNotification。然后,您可以使用 mixin 模式为每个接口实例提供 send 方法的默认实现:

interface ISmsNotifier
{
  int SmsId { get; }
  string SmsName { get; }
}

static class ISmsNotifierExtensions 
{
  public static bool NotifySms(this ISmsNotifier obj) 
  {
    var sender = new SendSMS();
    return sender.Send(obj);
  }
}

// ---------------------------------------------

interface IPushNotifier 
{
  int PushAccNum { get; }
  string PushName { get; }
}

static class IPushNotifierExtensions 
{
  public static bool NotifyPush(this IPushNotifier obj) 
  {
    var sender = new SendEmail();
    return sender.Send(obj);
  }
}

// ---------------------------------------------

interface IEmailNotifier 
{
  string EmailAddress { get; }
  string EmailPhone { get; }
}

static class IEmailNotifierExtensions 
{
  public static bool NotifyEmail(this IEmailNotifier obj) 
  {
    var sender = new SendEmail();
    return sender.Send(obj);
  }
}

然后您可以在objX像这样的类:

public class obj1 : INotifier, ISmsNotifier 
{
  public int SmsId { get; set; }
  public string SmsName { get; set; }

  public bool Notify() => this.NotifySms();
}

public class obj2 : INotifier, IPushNotifier
{
    public int PushAccNum { get; set; }
    public string PushName { get; set; }

    public bool Notify() => this.NotifyPush();
} 

public class obj3 : INotifier, IEmailNotifier
{
    public string EmailAddress { get; set; }
    public string EmailPhone { get; set; }

    public bool Notify() => this.NotifyEmail();
}

请注意,使用这种方法不仅可以轻松支持使用相同通知系统的对象,还可以支持具有以下功能的对象:multiple通知系统:

public class obj4 : INotifier, IEmailNotifier, IPushNotifier
{
    public int PushAccNum { get; set; }
    public string PushName { get; set; }
    public string EmailAddress { get; set; }
    public string EmailPhone { get; set; }

    public bool Notify() => this.NotifyEmail() && this.NotifyPush();
}

您可能会注意到这种方法使得NotificationHelper已过时,因为不再需要通过处理步骤传递对象来确定通过哪个通知系统处理对象。这是真的,也许也是正确的,因为对象应该完全能够自己决定这一点(取决于你处理这个问题的心态)。然而,NotificationHelper可能仍然有其用途,例如,如果您想要预处理发送到通知服务的信息,或者如果您想要一个公共入口点来帮助模拟和测试。

C#8 注意:

C# 8 的一项拟议功能是能够为接口提供接口定义本身内方法的默认实现。当(如果)发生这种情况时,您不需要再使用 mixin 模式,并且可以直接在接口中定义默认方法实现。该功能尚未最终确定,但它可能看起来像这样:

interface ISmsNotifier 
{
  int SmsId { get; }
  string SmsName { get; }

  public bool NotifySms() 
  {
    var sender = new SendSMS();
    return sender.Send(this);
  }
}

// ---------------------------------------------

interface IPushNotifier 
{
  int PushAccNum { get; }
  string PushName { get; }

  public bool NotifyPush() 
  {
    var sender = new SendEmail();
    return sender.Send(this);
  }
}

// ---------------------------------------------

interface IEmailNotifier 
{
  string EmailAddress { get; }
  string EmailPhone { get; }

  public bool NotifyEmail() 
  {
    var sender = new SendEmail();
    return sender.Send(this);
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# - 通过相同的方法传递不同类型的对象 的相关文章

  • 检查列表是否包含另一个列表。 C#

    编辑 只是说 ContainsAllItem 中的注释解释得最好 很抱歉问这个问题 我知道以前有人问过这个问题 但我只是不明白 好的 所以我想检查一个列表是否包含另一个列表中的所有项目WITHOUT重叠 以及根据类字符串 名称变量 称为项目
  • 切换图片框可见性 C#

    为什么图片框控件的可见性属性在这里不起作用 我最初将它们设置为 false 以便在屏幕加载时它们不可见 但后来我想切换这个 我已完成以下操作 但似乎不起作用 这是一个 Windows 窗体应用程序 private void Action w
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读
  • 返回 int& 的函数[重复]

    这个问题在这里已经有答案了 我在网上查了一下发现一篇试图解释的文章std move和右值 http thbecker net articles rvalue references section 01 html并发现了一些我实在无法掌握的东
  • 通过引用传递时取消引用指针

    当通过引用传递给函数时取消引用指针时会发生什么 这是一个简单的例子 int returnSame int example return example int main int inum 3 int pinum inum std cout
  • 如何在 Windows 窗体中运行屏幕保护程序作为其背景?

    如何在 Windows 窗体中运行屏幕保护程序作为其背景 用户还可以在屏幕保护程序运行时与表单控件进行交互 为什么这个 我们有一个案例 需要在用户时运行 Windows Bubbles 屏幕保护程序 可以继续与表单控件交互吗 您可以使用以下
  • 在通过网络发送之前压缩位图

    我正在尝试通过网络发送位图屏幕截图 因此我需要在发送之前对其进行压缩 有一个库或方法可以做到这一点吗 当您将图像保存到流时 您have选择一种格式 几乎所有位图格式 bmp gif jpg png 都使用一种或多种压缩形式 因此 只需选择适
  • 导出到 CSV 时 Gridview 出现空行

    这个问题是由进一步讨论引发的这个问题 https stackoverflow com questions 6674555 export gridview data into csv file 6674589 noredirect 1 com
  • Microsoft.Graph - 如何从具有不同用户名的共享邮箱发送?

    我目前正在将使用 SMTP 的服务代码移植到 Office 365 通过 SMTP 我可以使用 发件人 字段在来自共享收件箱的邮件上设置不同的用户名 同时保留共享电子邮箱地址 这似乎无法通过 Office 365 运行 其工艺流程为 客户填
  • c# 如何生成锦标赛括号 HTML 表

    所以我已经被这个问题困扰了三个星期 但我一生都无法弄清楚 我想做的是使用表格获得这种输出 演示 http www esl world net masters season6 hanover sc2 playoffs rankings htt
  • 更改其他页面的主窗口内容

    在 WPF 应用程序的主窗口中 我有一个 Badged 元素 来自材料设计 这是我的代码
  • C# 中处理 SQL 死锁的模式?

    我正在用 C 编写一个访问 SQL Server 2005 数据库的应用程序 该应用程序是数据库密集型的 即使我尝试优化所有访问 设置适当的索引等 我预计迟早会遇到死锁 我知道为什么会发生数据库死锁 但我怀疑我能否在某个时候发布不发生死锁的
  • realloc():重新分配为 char * 上的 strcat 腾出空间时下一个大小无效 [重复]

    这个问题在这里已经有答案了 我在以下代码中收到无效内存错误 printf s n FINE 5 printf s LENGTH IS d n FINE 6 strlen buffer char realloc buffer strlen b
  • Dynamics Crm:获取状态代码/状态代码映射的元数据

    在 Dynamics CRM 2011 中 在事件实体上 状态原因 选项集 也称为状态代码 与 状态 选项集 也称为状态代码 相关 例如看这个截图 当我使用 API 检索状态原因选项集时 如下所示 RetrieveAttributeRequ
  • 展开路径中具有环境变量的文件名

    最好的扩张方式是什么 MyPath filename txt to home user filename txt or MyPath filename txt to c Documents and settings user filenam
  • 微软语音识别速度

    我正在使用微软的语音识别器开发一个小型练习应用程序 对于我正在做的事情来说 我似乎无法让它足够快地识别单个单词 我希望能够正常说话 系统将从我所说的内容中抓取 关键字 并生成一个字符串 目前我正在使用 5 个单词的自定义语法 红 蓝 黄 绿
  • 为什么C语言中可以使用多个分号?

    在 C 中我可以执行以下操作 int main printf HELLO WORLD 它有效 这是为什么 我个人的想法 分号是一个 NO OPERATION 来自维基百科 指示符 拥有一大串分号与拥有一个分号并告诉 C 语句已结束具有相同的
  • 检测 SignalR Hub 客户端立即断开连接

    SignalR Hub OnDisconnected 何时在服务器端引发 对于崩溃或关闭而不调用Stop method 我正在使用 SignalR NET 客户端进行测试 而不是 javascript 客户端 如果我打电话给Stop客户端上
  • c# 替代方案中 cfusion_encrypt 中填充的密钥是什么?

    我找到了从这里复制 C 中的 cfusion encrypt 函数的答案 ColdFusion cfusion encrypt 和 cfusion decrypt C 替代方案 https stackoverflow com questio
  • 创建带有部分的选项卡式侧边栏 WPF

    我正在尝试创建一个带有部分的选项卡式侧边栏 如 WPF 中的以下内容 我考虑过几种方法 但是有没有更简单 更优雅的方法呢 方法一 列表框 Using a ListBox并将 SelectedItem 绑定到右侧内容控件所绑定的值 为了区分标

随机推荐