3

我正在寻找一个定义对象持有结构的类。此对象的值可以在创建此容器的时间之后设置。在 lambdas 或回调函数等中传递这样的结构很有用。

说:

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

定义这种结构相当容易,但我想看看是否可以在 FCL 中使用。我还希望这是一个高效的结构,具有所有需要的特性,如线程安全、高效等待等。

任何帮助是极大的赞赏。

4

2 回答 2

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();
    }
}
于 2010-05-09T05:17:27.687 回答
3

你想要完成的事情感觉就像一个未来。.NET 4.0 TPL 的早期 CTP 有一个Future<T>类。在 .NET 4.0 的 RTM 中,它已重命名为Task<T>. 如果你眯着眼睛,你可以看到两者之间的相似之处:

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

如果您还没有使用 .NET 4.0,您可以下载.NET 3.5sp1 的反应式扩展。它包含一个 System.Threading.dll 程序集,其中包含 .NET 3.5 的 TPL。


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

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

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

var bytes = downloadBytesTask.Value;
于 2010-05-09T09:39:35.623 回答