2010-05-09 27 views
3

我正在寻找一个为对象定义保持结构的类。此对象的值可以在比创建此容器时更晚的时间设置。在lambda表达式或回调函数等.NET Framework中是否有任何类来表示对象的容器?

说通过这样的结构是非常有用的:

class HoldObject<T> { 
public T Value { get; set; } 
public bool IsValueSet(); 
public void WaitUntilHasValue(); 
} 

// and then we could use it like so ... 

HoldObject<byte[]> downloadedBytes = new HoldObject<byte[]>(); 
DownloadBytes("http://www.stackoverflow.com", sender => downloadedBytes.Value = sender.GetBytes()); 

这是相当容易定义这种结构,但我想看看是否一个整箱可用。我也希望这是一个高效的结构,具有所有需要的功能,如线程安全,高效的等待等。

任何帮助,非常感谢。

+4

我不认为我曾经见过这样的一类,在任何地方。 – 2010-05-09 05:12:01

+0

你所要求的是一个有效的缓冲区。你看过各种Stream对象吗? – slugster 2010-05-09 05:14:39

+0

@slugster:我不确定他们是如何完全相关的。 – 2010-05-09 23:16:52

回答

3

从来没有见过这样的班级,但应该很简单。

public class ObjectHolder<T> 
{ 
    private T value; 
    private ManualResetEvent waitEvent = new ManualResetEvent(false); 

    public T Value 
    { 
     get { return value; } 
     set 
     { 
      this.value = value; 

      ManualResetEvent evt = waitEvent; 

      if(evt != null) 
      { 
       evt.Set(); 
       evt.Dispose(); 
       evt = null; 
      } 
     } 
    } 

    public bool IsValueSet 
    { 
     get { return waitEvent == null; } 
    } 

    public void WaitUntilHasValue() 
    { 
     ManualResetEvent evt = waitEvent; 

     if(evt != null) evt.WaitOne(); 
    } 
} 
+0

感谢您的实施。我已经做了一个非常类似的impl,并且想知道它是否是一个常见的用途,因此需要一个标准的.NET类。 – 2010-05-09 08:04:49

+0

为什么不使用'任务'? (请参阅我的回答) – Steven 2010-05-09 09:41:27

+1

@Steven:因为它不符合OP的要求。没有setter,因为Task表示函数的返回值,而不是简单的值容器。 – 2010-05-09 13:41:47

3

你试图完成的感觉很像未来。 .NET 4.0 TPL的早期CTP有一个Future<T>类。使用.NET 4.0的RTM,它已更名为Task<T>。如果你不使用.NET 4.0还

class HoldObject<T> 
{ 
    public T Value { get; set; } 
    public bool IsValueSet(); 
    public void WaitUntilHasValue(); 
} 

class Task<T> 
{ 
    public T Value { get } 
    public bool IsCompleted { get; } 
    public void Wait(); 
} 

,您可以下载Reactive Extensions for .NET 3.5sp1:如果你眯着眼睛,你可以看到之间的相似之处。它包含一个包含TPL for .NET 3.5的System.Threading.dll程序集。


虽然 Value是只读的,但更改它当然可以通过您提供任务的委托的返回值来完成。当然,我不能完全肯定这是否符合您的要求,但你的例子可以按如下方式写入:

var downloadBytesTask = Task<byte[]>.Factory.StartNew(() => 
    DownloadBytes("http://www.stackoverflow.com")); 

if (!downloadBytesTask.IsCompleted) 
{ 
    downloadBytesTask.Wait(); 
} 

var bytes = downloadBytesTask.Value; 
+1

这是一个很好的答案,非常感谢。但是我的要求与此有点不同。仔细观察,我想要的是一个容器,它可以传递给一段可能在任何时候执行的代码,顺便说一下,这个值通常用于异步操作的回调。而任务是“可以返回一个值的那段代码的定义”。虽然它们在大多数情况下可以互换使用,但它们并不完全相同。另外,Task本身定义了一个不同的编程模型,这并不适合我所有的场景。 – 2010-05-09 23:37:33

相关问题