2015-06-08 14 views
9
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(); 
      } 


     } 

    } 
} 

Mam klasę wiadomości, w której użytkownik może zostawić wiadomość dla więcej niż jednej osoby. Mam na to zyski, jednak zwraca ConcurrentBag <> sposób, w jaki zrobiłem odpowiednią praktykę? Jeśli nie, w jaki sposób mogę zwrócić ConcurrentBag <>, aby móc go przeglądać i wyświetlać?C# Zwróć kopię z ConcurrentBag

Odpowiedz

6

ConcurrentBag<T> to IEnumerable<T>. Możesz go przeglądać jak zwykle. Jednak ponieważ jest to kolekcja bezpieczna dla wątków, istnieją obawy związane z wydajnością korzystania z niej.

Jeśli chcesz pozbyć się wpływu wydajności podczas pętli, zadzwoń pod numer ToArray i zamiast tego zwróć nową tablicę.

public IEnumerable<Employee> ReturnMessageFor 
    { 
     get 
     { 

      return messageFor.ToArray(); 
     } 

    } 
+0

Czy getter jest jednak bezpieczny dla wątków? Co jeśli wydajność nie jest problemem? Czy mógłbym zostawić gettera takim, jaki jest? –

+0

@Nexusfactor pozostawiając go tak, jak jest, jest w porządku, ale należy pamiętać, że zużywający się kod może następnie dodać nowe rzeczy do torby. Nie zawsze jest to pożądane. – Gusdor

+0

The messageFor (o ile widzę w twoim kodzie) zostanie utworzony tylko raz w ctor. Więc nie ma problemów z gwintowaniem. Problemy z wątkami wchodzą w grę, gdy obiekty są zmienne, ale w przypadku zbiorów, obiekty współbieżne są wyraźnie zadbane o te problemy. Kolejne pytanie brzmi, czy klasa pracownika jest zmienna i co się dzieje, gdy dwa wątki pracują nad nimi w tym samym czasie. – Oliver

2

Nie jest dla mnie jasne, co próbujesz osiągnąć.

Czy próbujesz uzewnętrznić torbę do wszystkich operacji? Ponieważ to właśnie zrobiłeś ...

Jeśli chcesz uzewnętrznić coś, co możesz powtórzyć, powinieneś zwrócić torbę jako IEnumerable lub zwrócić tablicę lub listę skopiowaną z torby.

W obu przypadkach można bezpiecznie iterować. Może nie być najlepszy pod względem wydajności, ale to kolejne pytanie.

// Option 1 
    public IEnumerable<Employee> ReturnMessageFor 
    { 
     get 
     { 
      return messageFor; 
     } 
    } 

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

Uwagi:

  • Możesz chcieć uczynić messageFor tylko do odczytu (w kodzie zamieszczonych jest tylko do odczytu).
  • Pamiętaj, że ConcurrentBag pozwala bezpiecznie przeglądać migawkę kolekcji w sposób bezpieczny dla wątków, ale nie blokuje elementów w kolekcji.
+0

Wszystko, czego chciałem, to pobrać kolekcję i powtórzyć ją. Jednak nie chcę, aby użytkownik zmodyfikował kolekcję w innym miejscu. Podoba mi się twoje drugie podejście. Zwraca tablicę i nie można jej zmodyfikować w żaden sposób, prawda? –

+0

Tak. ToArray zwraca _shallow copy_ kolekcji tak removeFor ​​nie można zmienić. –