2012-08-05 112 views
0

我試圖編譯由大師「喬·達菲」提出的代碼(More iterator fun with the producer/consumer pattern ),類生產者/消費者,但這種錯誤發生:
抽象類和非空值類型

(我正在使用visual studio 2010和net 4.0.3)

 
Program.cs(37,34): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable' 
Program.cs(11,40): (Related location) 
Program.cs(37,61): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable' 
Program.cs(11,40): (Related location) 
Program.cs(44,53): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable' 
Program.cs(11,40): (Related location) 

對於我微薄的知識來說太多了!有人可以提出解決方案嗎?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace ProducerConsumerClass 
{ 
    class Program 
    { 
     public abstract class Producer<T> 
     { 
      public Producer() 
      { 
       worker = new Thread(new ThreadStart(this.ProductionCycle)); 
      } 
      private Queue<T> buffer = new Queue<T>(); 
      public Thread worker; 
      private bool done; 
      public bool Done 
      { 
       get 
       { 
        return done; 
       } 
      } 

      public IEnumerable<T> ConsumerChannel 
      { 
       get 
       { 
        if (done) 
         throw new InvalidOperationException("Production is not currently active"); 

        while (!done) 
        { 
         Nullable<T> consumed = new Nullable<T>(); 

         //BUG: compiler crashes when using lock(...) construct within iterator 
         Monitor.Enter(buffer); 
         if (buffer.Count == 0) 
          Monitor.Wait(buffer); 
         if (buffer.Count > 0) 
          consumed = new Nullable<T>(buffer.Dequeue()); 
         Monitor.Exit(buffer); 

         if (consumed.HasValue) 
          yield return consumed.Value; 
        } 

        yield break; 
       } 
      } 

      public void BeginProduction() 
      { 
       done = false; 
       worker.Start(); 
      } 

      public void EndProduction() 
      { 
       done = true; 
       lock (buffer) 
       { 
        Monitor.PulseAll(buffer); 
       } 
      } 

      private void ProductionCycle() 
      { 
       while (!done) 
       { 
        T t = ProduceNext(); 
        lock (buffer) 
        { 
         buffer.Enqueue(t); 
         Monitor.Pulse(buffer); 
        } 
       } 
      } 

      protected abstract T ProduceNext(); 

     } 

     public abstract class Consumer<T> 
     { 
      public Consumer(Producer<T> producer) 
      { 
       this.producer = producer; 
       worker = new Thread(new ThreadStart(this.ConsumerCycle)); 
      } 

      private Producer<T> producer; 

      public Thread worker; 

      private bool done = false; 

      public bool Done 
      { 
       get 
       { 
        return done; 
       } 
      } 

      public void BeginConsumption() 
      { 
       done = false; 
       worker.Start(); 
      } 

      public void EndConsumption() 
      { 
       done = true; 
      } 

      private void ConsumerCycle() 
      { 
       foreach (T t in producer.ConsumerChannel) 
       { 
        Consume(t); 
        if (done) 
         break; 
       } 
      } 

      protected abstract void Consume(T t); 
     } 

     class RandomNumberProducer : Producer<int> 
     { 
      public RandomNumberProducer() 
       : base() 
      { 
       rand = new Random(); 
      } 

      private Random rand; 

      protected override int ProduceNext() 
      { 
       return rand.Next(); 
      } 
     } 

     class RandomNumberConsumer : Consumer<int> 
     { 
      public RandomNumberConsumer(RandomNumberProducer p) 
       : base(p) 
      { 
      } 

      private static int counter = 0; 

      private int id = ++counter; 

      protected override void Consume(int t) 
      { 
       Console.Out.WriteLine("#{0}: consumed {1}", id, t); 
      } 
     } 

     static void Main(string[] args) 
     { 
      RandomNumberProducer p = new RandomNumberProducer(); 

      RandomNumberConsumer c1 = new RandomNumberConsumer(p); 
      RandomNumberConsumer c2 = new RandomNumberConsumer(p); 
      RandomNumberConsumer c3 = new RandomNumberConsumer(p); 

      p.BeginProduction(); 

      c1.BeginConsumption(); 
      c2.BeginConsumption(); 
      c3.BeginConsumption(); 

      Thread.Sleep(2500); 

      c3.EndConsumption(); 
      c2.EndConsumption(); 
      c1.EndConsumption(); 

      p.EndProduction(); 
     } 
    } 
} 
+1

喬恩斯基特FTW:http://stackoverflow.com/questions/2230657/help-with-c-sharp-generics-error-the-type -t-must-be-a-non-nullable-value-ty – timothyclifford 2012-08-05 13:19:58

回答

4

需要約束T

public abstract class Producer<T> where T : struct 
public abstract class Consumer<T> where T : struct 
+1

@lsalamon此外,不是說'可空Nulllable 消費=新Nullable ();'更容易說(讀)'T?消耗=空;'。同樣,不是'消費=新可空(buffer.Dequeue());'只是說'消費= buffer.Dequeue();'。 – 2012-08-05 14:02:02