C #: WCF: Вопрос наследования интерфейса и приведение - PullRequest
0 голосов
/ 15 июля 2010

Я пишу на стороне клиента для службы WCF, которая поддерживает синхронные и асинхронные вызовы без необходимости реализации 5-6 различных методов в канале для каждого метода в контракте.

У меня есть базовый интерфейс (IServiceClient) и универсальный класс, основанный на этом типе интерфейса (ServiceClient), следующим образом:

public interface IServiceClient { /* nothing here -- just for casting purpose */ }

public abstract class ServiceClient<TChannel> : ClientBase<TChannel> where TChannel : class, IServiceClient
{
    ....

    public T SyncCall<T>(string method, object[] args)
    {
        ....
        return (T)...
    }

    public ServiceCall<T> AsyncCall<T>(string method, object[] args)
    {
        return new ServiceCall<T>(this, method, args);
    }

    ....

    public class ServiceCall<T>
    {
        public ServiceCall(RemoteServiceClient<TChannel> service, string method, object[] args)
        {
            ...
        }

        ...

        public PageAsyncTask CreatePageAsyncTask(Action<T> onSuccess, Action<Exception> onFailure)
        {
            return new System.Web.UI.PageAsyncTask(...);
        }
    }
}

Также имеется другой интерфейс (фактический контракт), расширяющий базовый интерфейс, и конкретная реализация класса ServiceClient, основанная напроизводный интерфейс выглядит следующим образом:

[ServiceContract]
public interface IMyServiceClient : IServiceClient
{
    ....

    [OperationContract]
    string GetWhatever(int index);
    [OperationContract]
    IAsyncResult BeginGetWhatever(int index, System.AsyncCallback callback, object asyncState);
    string EndGetWhatever(System.IAsyncResult result);

    ....
}


public partial class MyServiceClient : ServiceClient<IMyServiceClient>
{
    ....

    public string GetWhatever(int index)
    {
        return SyncCall<string>("GetWhatever", new object[] { index });
    }
    public ServiceCall<string> GetWhateverAsync(int index)
    {
        return AsyncCall<string>("GetWhatever", new object[] { index });
    }

    ....
}

Я пытаюсь вызвать метод GetWhwhat (int) асинхронно в моем элементе управления следующим образом:

public class MyWebControl : WebControl
{
    private void HandleFailure(System.Exception e) { .... }
    public void CallService<T>(ServiceClient<IServiceClient>.ServiceCall<T> func, System.Action<T> onSuccess, System.Action<Exception> onFailure)
    {
        this.Page.RegisterAsyncTask(func.CreatePageAsyncTask(onSuccess, onFailure ?? (e => this.HandleFailure(e))));
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        ....

        var client = new MyServiceClient(/*whatever*/);
        client.Open();
        CallService(client.GetWhateverAsync(index), this.OnResult, this.OnError);

        ....
    }

    public void OnResult(string result) { .... }
    public void OnError(Exception e) { .... }
}

Я получаю 2 ошибки компиляции:

Error 1 The best overloaded method match for 'MyWebControl.CallService<string>>(IServiceClient>.ServiceCall<string>, System.Action<string>, System.Action<System.Exception>)' has some invalid arguments
Error 2 Argument 1: cannot convert from 'ServiceClient<IMyServiceClient>.ServiceCall<string>' to 'ServiceClient<IServiceClient>.ServiceCall<string>'

Очевидно, что компилятор не может понять, что IMyServiceClient расширяет IServiceClient.Я понимаю, что наследование интерфейса не работает как наследование классов;но я не уверен, как обойти эту ошибку компилятора.Я уже пытался добавить новую реализацию ServiceCall внутри класса MyServiceClient, чтобы расширить ее в базе - но ошибка компилятора не изменилась.

Кстати, если я изменю свою реализацию ServiceClient на базу из IMyServiceClient, она работает.Кроме того, вызов только client.GetWhwhat (index) (который вызывает метод SyncCall) компилируется и работает просто отлично.

Может помочь любая идея о том, что происходит или что ищет компилятор.Спасибо.

Ответы [ 2 ]

1 голос
/ 15 июля 2010

Проблема не имеет ничего общего с наследованием интерфейса. Это факт, что дженерики, как правило, не являются ковариантными : ServiceClient<IMyServiceClient> не может быть приведено к ServiceClient<IServiceClient>, даже если IMyServiceClient наследуется от IServiceClient

0 голосов
/ 15 июля 2010

Решил, изменив метод CallService в моем элементе управления:

public void CallService<TChannel, T>(ServiceClient<TChannel>.ServiceCall<T> func, System.Action<T> onSuccess, System.Action<Exception> onFailure) where TChannel: class, IServiceClient
{ 
    this.Page.RegisterAsyncTask(func.CreatePageAsyncTask(onSuccess, onFailure ?? (e => this.HandleFailure(e)))); 
} 

Thx.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...