【问题标题】:C# Return a Copy of ConcurrentBagC# 返回 ConcurrentBag 的副本
【发布时间】:2015-06-08 20:17:48
【问题描述】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace Crystal_Message
{
    class Message
    {
        private int messageID;
        private string message;
        private ConcurrentBag <Employee> messageFor;
        private Person messageFrom;
        private string calltype;

        public Message(int iden,string message, Person messageFrom, string calltype, string telephone)
        {
            this.messageID = iden;
            this.messageFor = new ConcurrentBag<Employee>();
            this.Note = message;
            this.MessageFrom = messageFrom;
            this.CallType = calltype;
        }

        public ConcurrentBag<Employee> ReturnMessageFor
        {
            get
            {

                return messageFor;
            }

        }

        public int MessageIdentification
        {
            get { return this.messageID; }

            private set
            {
                if(value == 0)
                {
                    throw new ArgumentNullException("Must have Message ID");
                }

                this.messageID = value;
            }

        }

        public string Note
        {
            get { return message; }

            private set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    throw new ArgumentException("Must Have a Message");

                }
                this.message = value;


            }

        }

        public Person MessageFrom
        {
            get { return messageFrom; }

            private set
            {
                this.messageFrom = value;
            }

        }

        public string CallType
        {
            get { return this.calltype; }

            private set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    throw new ArgumentNullException("Please specify call type");
                }

                this.calltype = value;

            }

        }

        public void addEmployee(Employee add)
        {
            messageFor.Add(add);
        }


        public override string ToString()
        {
            return "Message: " + this.message + " From: " + this.messageFrom + " Call Type: " + this.calltype + " For: " + this.returnMessagefor();
        }

        private string returnMessagefor() 
        {
            string generate="";

            foreach(Employee view in messageFor)
            {
                generate += view.ToString() + " ";
            }

            return generate;
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            Message testEquals = obj as Message;

            if((System.Object)testEquals == null)
            {
                return false;
            }

            return (this.messageID == testEquals.messageID) && (this.message == testEquals.message) && (this.messageFor == testEquals.messageFor) && (this.messageFrom == testEquals.messageFrom) && (this.calltype == testEquals.calltype);

        }

        public bool Equals(Message p)
        {
            if ((Object)p == null)
            {
                return false;
            }

            return (this.messageID == p.messageID) && (this.message == p.message) && (this.messageFor == p.messageFor) && (this.messageFrom == p.messageFrom) && (this.calltype == p.calltype);

        }

        public override int GetHashCode()
        {


            unchecked
            {
                return this.messageID.GetHashCode() * 33 ^ this.message.GetHashCode() * 33 ^ this.messageFor.GetHashCode() * 33 ^ this.messageFrom.GetHashCode() * 33 ^ this.calltype.GetHashCode();
            }


        }

    }
}

我有一个 Message 类,用户可以在其中为多个人留言。我有一个吸气剂,但是,是否以我正确练习的方式返回 ConcurrentBag ?如果没有,我如何返回 ConcurrentBag 以便循环遍历并显示它?

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    ConcurrentBag&lt;T&gt; 是一个IEnumerable&lt;T&gt;。你可以像往常一样循环遍历它。但是,由于这是一个线程安全的集合,因此使用它存在性能问题。

    如果您想消除循环时对性能的影响,请在其上调用 ToArray 并返回新数组。

        public IEnumerable<Employee> ReturnMessageFor
        {
            get
            {
    
                return messageFor.ToArray();
            }
    
        }
    

    【讨论】:

    • getter 线程安全吗?如果性能不是问题怎么办?我可以让吸气剂保持原样吗?
    • @Nexusfactor 保持原样就好了,但请注意,使用代码可以将新项目添加到包中。这并不总是可取的。
    • messageFor(据我在您的代码中所见)只会在 ctor 中创建一次。所以没有线程问题。当对象是可变的时,线程问题就会发挥作用,但在集合的情况下,并发的会明确地处理这些问题。另一个问题是,如果您的 Employee 类是可变的,如果两个线程同时在它们上工作会发生什么。
    • ToArray() 不是 Linq 扩展方法。它内置于ConcurrentBag&lt;T&gt;。 (如果它实际上是一个 Linq 扩展,那么它不会消除循环时的性能影响,因为 Linq 只是相当于一个 foreach anwyay)
    • @Nexusfactor 请仔细阅读文档,如果您仍然卡住,请提出另一个问题。
    【解决方案2】:

    我不清楚你想要完成什么。

    您是否尝试将 Bag 外部化以进行所有操作?因为你就是这么做的……

    如果您想将可以迭代的东西外部化,您应该将 Bag 作为 IEnumerable 返回,或者返回从 Bag 复制的数组或列表。

    无论哪种方式,迭代都是安全的。就性能而言可能不是最好的,但这是另一个问题。

        // Option 1
        public IEnumerable<Employee> ReturnMessageFor
        {
            get
            {
                return messageFor;
            }
        }
    
        // Option 2
        public Employee[] ReturnMessageFor
        {
            get
            {
                return messageFor.ToArray();
            }
        }
    

    注意事项:

    • 您可能希望将 messageFor 设为只读(在您发布的代码中它是只读的)。
    • 请记住,ConcurrentBag 允许您以线程安全的方式安全地迭代集合的快照,但它不会锁定集合中的项目。

    【讨论】:

    • 我想要的只是获取集合并对其进行迭代。但是,我不希望用户在其他地方修改集合。我喜欢你的第二种方法。返回一个数组,无论如何你都不能修改 messagefor 对吧?
    • 是的。 ToArray 返回集合的浅拷贝,因此无法更改 removeFor。
    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多