问题描述:

I'm trying to compile the code (More iterator fun with the producer/consumer pattern

) proposed by the guru 'Joe Duffy', for class producer / consumer, but this error is occurring:

(I'm using visual studio 2010 and 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)

Is too much for my meager knowledge! Could someone suggest a solution?

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

}

}

}

网友答案:

You need to constrain T:

public abstract class Producer<T> where T : struct
public abstract class Consumer<T> where T : struct
相关阅读:
Top