c# – 棘手的IDisposable问题

我正在尝试抽象/封装以下代码,因此所有客户端调用都不需要重复此代码.例如,这是一个从视图模型(MVVM)到WCF服务的调用:

using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
{
    var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
    IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));    
    this.Applications = new ObservableCollection<Application>(prestoService.GetAllApplications().ToList());
}

我最初的重构尝试是这样做:

public static class PrestoWcf
{
    public static IPrestoService PrestoService
    {
        get
        {
            using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
            {
                var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];    
                return channelFactory.CreateChannel(new EndpointAddress(endpointAddress));
            }
        }
    }
}

这允许我的视图模型现在只用一行代码进行调用:

this.Applications = new ObservableCollection<Application>(PrestoWcf.PrestoService.GetAllApplications().ToList());

但是,我收到WcfChannelFactory已经处理的错误.这是有道理的,因为当视图模型试图使用它时它确实被处理掉了.但是,如果我删除使用,那么我没有正确处理WcfChannelFactory.注意,当调用CreateChannel()时,WcfChannelFactory将自身嵌入到WcfClientProxy中.这就是视图模型在处理后尝试使用它的原因/方式.

如何正确处理WcfChannelFactory,如何抽象此代码,以使我的视图模型调用尽可能简单?我希望我解释得这么好.

编辑 – 解决了!

根据牛排回答,这样做了:

public static class PrestoWcf
{
    public static T Invoke<T>(Func<IPrestoService, T> func)
    {
        using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
        {
            var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];

            IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));
            return func(prestoService);
        }
    }
}

这是视图模型调用:

this.Applications = new ObservableCollection<Application>(PrestoWcf.Invoke(service => service.GetAllApplications()).ToList());
最佳答案
像下面这样的东西可能会有所帮助

public static void UsePrestoService(Action<IPrestoService> callback)
{
    using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
    {
        var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
        IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));  
        //Now you have access to the service before the channel factory is disposed.  But you don't have to worry about disposing the channel factory.
        callback(prestoService);
    }
}

UsePrestoService(service => this.Applications = new ObservableCollection<Application>(service.GetAllApplications().ToList()));

边注:

我没有在一次性用品上使用这种模式,因为我最近没有找到太多需要的一次性用品.但是,从理论上讲,我认为我喜欢这种模式,在使用一次性物品时,在一个使用块内执行回调有两个原因:

>这很简单
>它迫使IDisposables的消费者处置
    实例正确……虽然我同意(我认为)与C#的团队
    不处理IDisposable时不要引发编译器警告
    在所有执行路径中,它仍然有点令人担忧.

转载注明原文:c# – 棘手的IDisposable问题 - 代码日志