Есть ли способ наследовать класс без конструкторов в .NET? - PullRequest
7 голосов
/ 30 декабря 2008

В настоящее время я пытаюсь изменить некоторые функции HttpWebRequest, но я не могу сделать это с помощью наследования, поскольку HttpWebRequest не имеет открытых конструкторов (кроме конструктора десериализации). Есть ли обходной путь для этого?

Моя цель - написать код, подобный приведенному ниже, но объекты этого класса должны наследовать свойства и методы HttpWebRequest:

using System;
using System.Net;
using System.Threading;

public class AsyncWebRequest:WebRequest
{
    private readonly AsyncCallback getResponseCallback;
    private readonly Uri uri;
    private volatile int RetriesLeft = 3;
    private volatile WebRequest request;

    public AsyncWebRequest(string uri, AsyncCallback getResponseCallback)
       :this(new Uri(uri), getResponseCallback)
    {
    }

    public AsyncWebRequest(Uri uri, AsyncCallback getResponseCallback):base()
    {
        this.uri = uri;
        this.getResponseCallback = getResponseCallback;
    }

    private IAsyncResult BeginGetResponse()
    {
        request = HttpWebRequest.CreateDefault(uri);
        ((HttpWebRequest)request).ReadWriteTimeout = Timeout;
        var result = request.BeginGetResponse(GetResponseCallback, null);
        ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle,
            GetResponseTimeout, null, Timeout, true);
        return result;
    }

    private void GetResponseTimeout(object state, bool timedOut)
    {
        if (timedOut)
        {
            Retry();
        }
    }

    private void Retry()
    {
        request.Abort();
        bool retry = false;
        lock (request)
        {
            if (RetriesLeft > 0)
            {
                Interlocked.Decrement(ref RetriesLeft);
                retry = true;
            }
        }
        if (retry)
        {
            BeginGetResponse();
        }
        else
        {
            getResponseCallback(null);
        }
    }

    private void GetResponseCallback(IAsyncResult AsyncResult)
    {
        try
        {
            getResponseCallback(AsyncResult);
        }
        catch(WebException webException)
        {
            Retry();
        }
    }
}

Ответы [ 2 ]

12 голосов
/ 30 декабря 2008

Вы не можете с помощью наследования от HttpWebRequest (если вы не хотите вызывать конструктор сериализации), но вы можете с помощью композиции и делегирования, а также с помощью наследования от WebRequest (я не уверен, что это будет делать для Вы, но функционально это довольно похоже). В WebRequest есть конструктор по умолчанию.

В этом случае у вас не может быть класса «быть» HttpWebRequest (как в отношении is-a), поскольку вы не можете расширять его, но он будет «веб-запросом», которого должно быть достаточно .

Вы можете написать класс, который наследует от WebRequest, который имеет член экземпляра типа WebRequest, создать HttpWebRequest и назначить члену экземпляра в конструкторе нового типа и делегировать все вызовы этой ссылке (своего рода шаблон декоратора). ):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace ClassLibrary1
{
    public class MyHttpWebRequest : WebRequest
    {
        private WebRequest request;

        public MyHttpWebRequest(string uri)
        {
            request = HttpWebRequest.Create(uri);
        }

        public override WebResponse GetResponse()
        {
            // do your extras, or just delegate to get the original code, as long
            // as you still keep to expected behavior etc.
            return request.GetResponse();
        }

    }
}
4 голосов
/ 30 декабря 2008

Если вы не можете обмануть конструктор сериализации для выполнения ваших ставок, то нет, нет никакого способа.

Конструкторы этого класса являются внутренними, поэтому вы не можете их вызывать.

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