C# 使用长时间运行的构造函数设计对象
我有一个类,该类旨在为在整个应用程序中多次使用的某些特定文件提供对某些元数据的快速访问。不幸的是,一些元数据只能通过长时间运行的方法调用来提取 我有另一个类为长时间运行的方法提供异步包装(可以是5分钟或更长时间,具体取决于文件的大小),但我正在尝试找出如何调用此异步方法,以及是否适合将其放入构造函数中,或者是否有适合此场景的更好设计模式 下面是一些伪代码,试图说明我的问题:C# 使用长时间运行的构造函数设计对象,c#,.net,design-patterns,.net-3.5,C#,.net,Design Patterns,.net 3.5,我有一个类,该类旨在为在整个应用程序中多次使用的某些特定文件提供对某些元数据的快速访问。不幸的是,一些元数据只能通过长时间运行的方法调用来提取 我有另一个类为长时间运行的方法提供异步包装(可以是5分钟或更长时间,具体取决于文件的大小),但我正在尝试找出如何调用此异步方法,以及是否适合将其放入构造函数中,或者是否有适合此场景的更好设计模式 下面是一些伪代码,试图说明我的问题: public class MetaData { public string Data1 { get; privat
public class MetaData
{
public string Data1 { get; private set; }
public string Data2 { get; private set; }
public MetaData(String filepath)
{
var extractor = new ExtractMetaData(filepath); //create instance of class that fetches the metadata
this.Data1 = extractor.GetData1(); // short running method
extractor.Data2Received += Data2Received;
extractor.GetData2Async(); // long running method, called with via async method
}
private void Data2Received(object sender, MetaDataEventArgs args)
{
this.Data2 = args.Data; // finally set Data2 property
}
}
class ExtractMetaData
{
public event Data2ReceivedEventHandler Data2Received;
public ExtractMetaData (string filePath) { }
public String GetData1(); // very fast method to get Data1
public void GetData2Async(); // very slow method to get Data2
}
我想知道的是,是否有更好的方法来实现这一点
现在使用我的代码,几乎不需要等待
元数据的构建,但是如果有人在GetData2Async()
方法返回并触发Data2Received
事件之前尝试访问MetaData.Data2
属性,他们将得到null
响应。但是如果他们在返回后调用if,它将包含正确的信息。由于实际上没有办法通知用户此方法已完成,我担心这会变成糟糕的用户体验,因为他们不必等待构造函数,而必须等待所有属性的设置。我认为您需要注意以下模式:延迟加载(只有在您真正需要时才调用“long”方法)和代理(如果需要,实现缓存层,隐藏内部实现,可能在对象底部有多种不同的模式)。如果您决定使用多个对象来确保整个功能,那么Facade也是一个合理的选择。首先,您说没有办法通知用户获取数据2
已完成。这不是真的,您可以使用任何方法通知用户,例如事件或任务
但是我认为你实际上应该重组你的类。你说获取Data2
需要很长时间,这很可能意味着它需要很多资源。因此,我认为你甚至不应该尝试初始化Data2
,除非你必须这样做。你怎么知道?用户必须告诉你。理想情况下,如果ser不需要数据2
,他甚至不能访问它,这意味着将元数据
分为两类:类似于基本元数据
和扩展元数据
,它们继承自基本元数据
在ExtendedMetaData
中,您可以通过某种方式通知用户初始化已完成(很可能是使用事件),也可以让构造函数等待初始化完成(您可以使用Monitor.wait()
和Monitor.Pulse()
来完成)
就个人而言,我认为最好的选择是,如果您有一个静态工厂方法,它将返回任务
。这样,用户可以同步(使用结果
)或异步(使用ContinueWith()
或等待
,如果它可用的话)。这在.Net 4.5中特别有用(因为等待
),但也是在.Net 4.0上。不幸的是,您问题上的标签表明您正在使用.Net 3.5,它没有任务
。如果可能,我建议您升级。您将得到关于这个问题的几个不同答案。以下是我的看法
在我看来,你不应该调用构造函数中的任何操作,比如你现在正在做的事情。你的元数据构造函数中的所有东西都不应该从这里开始
当您实例化一个对象时,它可能会抛出一个异常,这很好,但不会构造您的对象。一些最佳实践。构造函数应该是短期运行的,并且应该确保在构造函数之后创建对象图
再看看这个问题:
或者,您应该注入依赖项并创建方法来填充数据
如果你能多描述一下你的问题,那会更有帮助
您确实需要简化流程和设计。我认为这取决于上下文,比如您提供的API类型,但我可能会以异步回调形式或阻塞标准调用的形式提供调用。我认为在这种情况下,包装器不会真的获得任何好处,除非您愿意由于能够返回部分答案,我认为您无法真正设计解决方案。仅凭我的意见,但我会将选项留给调用者,并将精力集中在优化该例程上。@Tim包装器实际上是我为其他目的编写的独立库的一部分,只是碰巧提供了异步功能以避免bl锁定。这只是10秒或15秒的问题,我可能会选择阻塞方法,但当我意识到可能需要5分钟时,我开始考虑另一种方法(在构造函数中调用异步方法)抱歉,我想我想说的是,我不认为有任何技巧可以应用到包装器上,从而在客户端清晰度或性能方面获得任何好处(除非部分答案有一定的用处)。包装器本身仍然允许您将“呃,这个方法太慢了,所以我需要封装它”逻辑与解析逻辑分开,因此我相信这是值得的。@Tim至于优化例程,这是不可能的……实际的长时间运行的方法是一个我无法控制的外部库。我的选项实际上是“仅限,不限”在长时间运行的方法中获得的数据,或者是长执行时间的数据。我选择后者,因为额外的数据对于某些PAR非常有用。