【问题标题】:Is it possible to get rid of the TClient generic type in the Service class是否可以摆脱 Service 类中的 TClient 泛型类型
【发布时间】:2015-04-19 09:29:39
【问题描述】:

对于 WCF 客户端,我有一个 IServiceProxyFactory 接口来设置凭据。

public interface IServiceProxyFactory<T>
{
    T GetServiceProxy();
}

public class ServiceProxy1 : IServiceProxyFactory<ServiceClient1>
{
    public ServiceClient1 GetServiceProxy()
    {
        var client = new ServiceClient1();
        // set credentials here
        return client;
    }
}

public class ServiceProxy2 : IServiceProxyFactory<ServiceClient2> { 
    // ... 
} 

从问题What is the best workaround for the WCF client `using` block issue?,我创建了一个助手如下:

public static class Service<TProxy, TClient>
    where TProxy : IServiceProxyFactory<TClient>, new()
    where TClient : ICommunicationObject
{
    public static IServiceProxyFactory<TClient> proxy = new TProxy();

    public static void Use(Action<TClient> codeBlock)
    {
        TClient client = default(TClient);
        bool success = false;
        try
        {
            client = proxy.GetServiceProxy();
            codeBlock(client);
            ((ICommunicationObject)client).Close();
            success = true;
        }
        finally
        {
            if (!success)
            {
                ((ICommunicationObject)client).Abort();
            }
        }
    }
}

我将助手用作:

Service<ServiceProxy1, ServiceClient1>.Use(svc => svc.Method()); 

问题:

  1. 有没有办法让我摆脱 TClientTProxy(更新) 类型,以便我可以使用:

    Service<ServiceProxy1>.Use(svc => svc.Method()); 
    

    (更新)

    Service<ServiceClient1>.Use(svc => svc.Method()); 
    
  2. 有没有比将ICommunicationObject 用于Close()Abort() 更好的方法?

【问题讨论】:

  • 嗯……你能把类的约束改成IServiceProxy,把TClient从类签名中去掉,然后把TClient和约束加到方法里吗?

标签: c# wcf generics types


【解决方案1】:
  • 代码

    partial class TestClass {
        public static void TestMethod() {
            Service<ServiceProxy1>.Use(svc => svc.Method());
            Service<ServiceProxy1>.Use(svc => svc.Method());
            Service<ServiceProxy1>.Use(svc => svc.Method());
            Service<ServiceProxy2>.Use(svc => svc.Method());
        }
    }
    
    public partial interface IServiceProxyFactory<T> {
        T GetServiceProxy();
    }
    
    public partial class Service<T> where T: ServiceProxy, new() {
        public static void Use(Action<T> codeBlock) {
            using(var client=ServiceProxy.GetServiceProxy<T>().GetServiceProxy() as T)
                try {
                    codeBlock(client);
                }
                catch {
                    throw;
                }
        }
    }
    
    public abstract partial class ServiceProxy: CommunicationObject, IDisposable {
        public static T GetServiceProxy<T>() where T: ServiceProxy, new() {
            var proxy=m_List.FirstOrDefault(x => typeof(T).Equals(x.GetType())) as T;
    
            if(null==proxy) {
                proxy=new T();
                m_List.Add(proxy);
            }
    
            return proxy;
        }
    
        public abstract ServiceProxy GetServiceProxy();
        public abstract void Method();
    
        protected virtual void Dispose(bool disposing) {
            lock(ThisLock)
                if(!this.IsDisposed&&disposing) {
                    this.Close();
    
                    if(!this.IsDisposed)
                        this.Abort();
                }
        }
    
        public void Dispose() {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        ~ServiceProxy() {
            this.Dispose(false);
        }
    
        static List<ServiceProxy> m_List=new List<ServiceProxy>();
    }
    
    public partial class ServiceProxy1: ServiceProxy {
        protected override IAsyncResult OnBeginClose(
            TimeSpan timeout, AsyncCallback callback, object state
            ) {
            throw new NotImplementedException();
        }
    
        protected override IAsyncResult OnBeginOpen(
            TimeSpan timeout, AsyncCallback callback, object state
            ) {
            throw new NotImplementedException();
        }
    
        protected override void OnAbort() {
        }
    
        protected override void OnEndClose(IAsyncResult result) {
        }
    
        protected override void OnEndOpen(IAsyncResult result) {
        }
    
        protected override void OnClose(TimeSpan timeout) {
        }
    
        protected override void OnOpen(TimeSpan timeout) {
        }
    
        protected override TimeSpan DefaultCloseTimeout {
            get {
                return TimeSpan.Zero;
            }
        }
    
        protected override TimeSpan DefaultOpenTimeout {
            get {
                return TimeSpan.Zero;
            }
        }
    
        public override ServiceProxy GetServiceProxy() {
            var client=new ServiceProxy1();
            // set credentials here
            return client;
        }
    
        public override void Method() {
        }
    }
    
    public partial class ServiceProxy2: ServiceProxy1 {
        public override ServiceProxy GetServiceProxy() {
            var client=new ServiceProxy2();
            // set credentials here
            return client;
        }
    }
    

有一点要提:

  1. lock 可以安全重新输入

  2. 我不可能对从T 到任何Generic&lt;T&gt; 的类型(例如从ServiseClientServiceProxy&lt;ServiceClient&gt;)进行完全相同的反转 推理声明.

  3. 根据2,ServiceProxyServiceClient在代码中是一样的,所以没有ServiceClient

  4. ServiceProxy 本身是抽象的。对于ServiceClient的要求,需要转换成ICommunicationObject,为了方便,根据3 plus,ServiceProxy派生自CommunicationObject;然后对于 有没有比 ... 更好的方法,它实现了IDisposible

  5. 对于继承ServiceProxy的具体类的静态实例,每个实例只有一个实例,并存储在m_List中,并调用GetServiceProxy&lt;T&gt;() 的静态通用版本就可以了。这看起来更像是享元模式。

  6. 根据5,接口IServiceProxyFactory&lt;T&gt;根本没用,放在那里看感觉开心。

  7. GetServiceProxy() 的实例版本保持原来的用法,但具体类需要覆盖它。

  8. Use 方法中,创建的客户端与using 语句一起使用。我已阅读Avoiding Problems with the Using Statement,但似乎我不知道您想要处理异常的策略,因此我只是tryrethrow

  9. 根据 1,我认为 线程安全 方式通过锁定以原子方式处理,使用继承的 IsDisposedThisLockCloseAbort 正在相应地进行操作。

  10. 哦,十个! ServiceProxy2ServiceProxy1 类仅用于示例,ServiceProxy2 派生自 ServiceProxy1

代码看起来很冗长,但实际上设计非常简单。只需报告我的问题,我会尽力纠正它。 Wish 能帮上忙 LOCK

【讨论】:

  • 仅供参考:第 8 点:Dispose 永远不应该抛出,更重要的是,您应该能够安全地多次调用 Dispose 已经处理的对象。不存在“使用 Using 隐藏异常”之类的问题 - 问题在于 Dispose 方法的无效实现
  • @quetzalcoatl:哦,当然。我主要假设我不知道是否有任何可能抛出,甚至在处置之前。所以留下一个 try and rethrow 应该是适用的方式。非常感谢!
  • @KenKin,我最终在下面给出了我的答案。但是你对partial 的使用让我朝着正确的方向前进,所以我要给你赏金。
【解决方案2】:

我通过使用ServiceClient1 : IServiceProxyFactory&lt;ServiceClient1&gt; 技巧将ServiceProxy1 类合并到ServiceClient1 中实现了它。

public interface IServiceProxyFactory<T>
{
    // can have a better name like SetCredentials()
    T GetServiceProxy();
}

// Got rid of ServiceProxy1 class
public partial class ServiceClient1 : IServiceProxyFactory<ServiceClient1>
{
    public ServiceClient1 GetServiceProxy()
    {
        var client = this;
        // set credentials here
        //client.ClientCredentials = "";
        return client;
    }
}

public partial class ServiceClient2 : IServiceProxyFactory<ServiceClient2> { ... } 

public static class ServiceMod<TClient>
    where TClient : class, ICommunicationObject, IServiceProxyFactory<TClient>, new()
{
    public static TReturn Use<TReturn>(Func<TClient, TReturn> codeBlock)
    {
        TClient client = default(TClient);
        bool success = false;
        try
        {
            client = new TClient().GetServiceProxy();
            TReturn result = codeBlock(client);
            client.Close();
            success = true;
            return result;
        }
        finally
        {
            if (!success)
            {
                client.Abort();
            }
        }
    }
}

现在我可以做到了:

Service<ServiceClient1>.Use(svc => svc.Method());

【讨论】:

  • 感谢赏金,自学者也不错。此外,我实际上首先发现它应该是Service&lt;ServiceClient1&gt;.Use(svc =&gt; svc.Method());,因为原始问题中Action&lt;T&gt;的签名。所以我认为唯一可能的事情是ServiceProxyServiceClient 是同一件事。
猜你喜欢
  • 1970-01-01
  • 2017-04-30
  • 2013-03-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多