【问题标题】:IEnumerable how to add item to list [duplicate]IEnumerable如何将项目添加到列表[重复]
【发布时间】:2019-05-12 07:38:25
【问题描述】:

我有如下所示的界面。问题出在AddLogger() 方法中,我不能只使用Loggers.Add(logger);

public interface INotificationFactory
{
    IEnumerable<ILogger> Loggers
    {
        get;
        set;
    }
    void AddLogger(ILogger logger);
    void DoLog(EMsgType msgType, string msg);
    IEnumerable<ILogger> GetLoggers();
}

接口实现:

public class NotificationFactory : INotificationFactory
{
    public IEnumerable<ILogger> Loggers  // read-write instance property
    { get; set; }

    public NotificationFactory()
    {
        Loggers = new List<ILogger>();
    }


    public void AddLogger(ILogger logger)
    {
        Loggers.Add(logger);
    }

    public void DoLog(EMsgType msgType, string msg)
    {
        foreach (var logger in Loggers)
        {
            logger.Write(msgType, msg);
        }
    }

    public IEnumerable<ILogger> GetLoggers()
    {
        return Loggers;
    }
}

【问题讨论】:

  • Loggers.ToList().Add(logger);
  • hmm 但是 Loggers 变成 List 而不是 IEnumerable?这是正确的方法吗?
  • @Rahul 这只会将一个项目添加到要立即进行垃圾收集的列表中。

标签: c#


【解决方案1】:

我建议重新设计:

界面:

public interface INotificationFactory
{
    IEnumerable<ILogger> Loggers
    {
       get;
       set; // <- Remove it if it's possible
    }

    void AddLogger(ILogger logger);
    void DoLog(EMsgType msgType, string msg);

    // Remove it if it's possible: Loggers is enough
    IEnumerable<ILogger> GetLoggers();  
}

实施:

public class NotificationFactory : INotificationFactory
{
    // backing field: List<T> is by far more convenient than IEnumerable<T>
    private List<ILogger> m_Loggers = new List<ILogger>();  

    // Read-only: we don't want someone change the collection and removing items from it:
    public IReadOnlyList<ILogger> Loggers { 
        get {
            return m_Loggers;
        } 
    }

    IEnumerable<ILogger> INotificationFactory.Loggers {
        get {
            return m_Loggers;
        } 
        set {
            throw new NotSupportedException("Don't try to assign the collection"); 
        } 
    }

    // The only way to add an item - logger - is this direct call  
    public void AddLogger(ILogger logger)
    {
        if (null == logger)
            throw new ArgumentNullException(nameof(logger));

        // Just adding a logger - nothing to write home about
        m_Loggers.Add(logger);
    }

    public void DoLog(EMsgType msgType, string msg)
    {
        foreach (var logger in m_Loggers)
        {
            logger.Write(msgType, msg);
        }
    }

    //TODO: Do you want it? Loggers property seems to be enough
    IEnumerable<ILogger> INotificationFactory.GetLoggers()
    {
        return m_Loggers;
    }
}

【讨论】:

  • 我从不同的文章中了解到,人们几乎总是习惯于将 IEnumerable 用于列表,也许是因为它可以转换为不同的集合类型(如 List/Array 等),因此我使用 IEnumerable 而不是直接作为返回类型列出。你能解释一下为什么大多数开发人员在他们的环境中使用 IEnumerable 而不是 List?
  • 应该可能会改变 - return m_Loggers;return m_Loggers.AsReadOnly();
  • @dev: 是的,方法(构造函数)的 输入参数 应该是 IEnumerable&lt;T&gt;,以便该方法可以与不同的集合一起使用。 私人 支持字段是另一回事:它只是private,即NotificationFactory私人业务。它永远不会被曝光。
  • @Rand Random:我的实现 IReadOnlyList&lt;T&gt; 仅防止偶发错误/拼写错误,例如 MyFactory.Loggers.RemoveAt(123);。您的建议 - AsReadOnly 更安全,但需要更多时间和内存(将复制集合)
  • 它会阻止这个((List&lt;ILogger&gt;)MyFactory.Loggers).RemoveAt(123) - 但是,它需要时间/内存 - OP 必须决定他想要它是 100% 安全还是 99% 安全 :) - 我倾向于将第二个私有化存储只读字段并在添加/删除操作时对其进行更新并返回只读字段
猜你喜欢
  • 2013-08-22
  • 1970-01-01
  • 2015-01-29
  • 2011-06-28
  • 2020-08-04
  • 1970-01-01
  • 2010-11-15
  • 2014-12-29
  • 2020-12-07
相关资源
最近更新 更多