【问题标题】:abstract class and non-nullable value type抽象类和不可为空的值类型
【发布时间】:2012-08-05 13:13:47
【问题描述】:

我正在尝试编译代码 (More iterator fun with the producer/consumer pattern ) 由大师 'Joe Duffy' 提出,用于类生产者/消费者,但出现此错误:

(我使用的是visual studio 2010和net 4.0.3)

Program.cs(37,34):错误 CS0453:类型“T”必须是不可为空的值类型才能在泛型类型或方法“System.Nullable”中用作参数“T” Program.cs(11,40):(相关位置) Program.cs(37,61):错误 CS0453:类型“T”必须是不可为空的值类型才能在泛型类型或方法“System.Nullable”中用作参数“T” Program.cs(11,40):(相关位置) Program.cs(44,53):错误 CS0453:类型“T”必须是不可为空的值类型才能在泛型类型或方法“System.Nullable”中用作参数“T” Program.cs(11,40):(相关位置)

对于我微薄的知识来说太多了!有人可以提出解决方案吗?

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();
        }
    }
}

【问题讨论】:

标签: c# multithreading class producer-consumer non-nullable


【解决方案1】:

你需要约束T:

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

【讨论】:

  • @lsalamon 另外,说Nullable&lt;T&gt; consumed = new Nullable&lt;T&gt;(); 更容易说(和阅读)T? consumed = null;。同样,不要说consumed = new Nullable&lt;T&gt;(buffer.Dequeue());,而是说consumed = buffer.Dequeue();
猜你喜欢
  • 2010-10-10
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 2011-06-14
  • 1970-01-01
  • 2017-06-16
  • 2018-05-03
  • 1970-01-01
相关资源
最近更新 更多