Is there any way to inherit a class without constructors in .NET?
Asked Answered
A

2

8

I'm currently trying to modify some HttpWebRequest functions, but I can't do it through inheritance because HttpWebRequest has no public constructors (besides the deserialization constructor). Is there a workaround to do this?

My objective is to code something like the example below, but this class objects must inherit the HttpWebRequest properties and methods:

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();
        }
    }
}
Autecology answered 30/12, 2008 at 15:32 Comment(0)
C
4

Unless you can trick the serialization constructor to do your bidding, then no, there is no way.

The constructors of that class are internal, so you have no way of calling them.

Classless answered 30/12, 2008 at 15:35 Comment(9)
Can't I use the following solution? #179145Autecology
Well, you can of course use reflection and similar things, but that's really going to cause more problems than it's worth in the long run. You're bypassing all configuration of the class, which may mean it's not in a consistent state at all.Classless
If one wants to be evil, one could declare a derived class Foo with a constructor something like Foo(int x) : Foo( ((String)null).Length ) { } and a destructor which copies this to a static location. Try to construct the instance, catch the exception, force a collection, wait for pending finalizers, and the static location will hold an instance of the derived class without any base-class constructors having run.Gresham
@Gresham Unfortunately there can be no loops in constructor calls.Jellyfish
@IS4: I don't see any loops in the above.Gresham
@Gresham Assuming you meant : this(, the constructor of Foo calls itself, forming a cycle. This results in a compiler error.Jellyfish
@IS4: Ah. I've used VB.NET much more than C#, though it's been awhile since I've looked much at either; the constructor semantics are a bit different. I think in C# the effect I was looking for could be accomplished by having an object field initializer which throws an exception, since I think in C# those run before the parent constructor call (whereas in VB.NET they run after).Gresham
@IS4: Alternatively, I think one could simply have a constructor which chains to another constructor, but includes within the chaining call a method that will throw an exception.Gresham
It doesn't matter, it won't compile since you have to call inherited constructors and in this case you can't.Classless
C
12

You can't through inheritance from HttpWebRequest (if you don't want to call the serialization constructor) , but you can through composition and delegation, and through inheritance from WebRequest (I'm not sure if that will do it for you, but functionally it is quite similar). WebRequest has a default constructor.

In this case you then can't have the class 'be' a HttpWebRequest (as in an is-a relationship), since you can't extend from it, but it wil 'be' a WebRequest, which should suffice.

You could write a class that inherits from WebRequest, that has an instance member of type WebRequest, create a HttpWebRequest and assign to instance member in the constructor of the new type and delegate all calls to that reference (sort of a decorator pattern):

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();
        }

    }
}
Capps answered 30/12, 2008 at 16:32 Comment(2)
He can also delegate the call to the serialization constructor through reflection using this method.Pandanus
+1 for this approach. I generally prefer composition over inheritance.Lone
C
4

Unless you can trick the serialization constructor to do your bidding, then no, there is no way.

The constructors of that class are internal, so you have no way of calling them.

Classless answered 30/12, 2008 at 15:35 Comment(9)
Can't I use the following solution? #179145Autecology
Well, you can of course use reflection and similar things, but that's really going to cause more problems than it's worth in the long run. You're bypassing all configuration of the class, which may mean it's not in a consistent state at all.Classless
If one wants to be evil, one could declare a derived class Foo with a constructor something like Foo(int x) : Foo( ((String)null).Length ) { } and a destructor which copies this to a static location. Try to construct the instance, catch the exception, force a collection, wait for pending finalizers, and the static location will hold an instance of the derived class without any base-class constructors having run.Gresham
@Gresham Unfortunately there can be no loops in constructor calls.Jellyfish
@IS4: I don't see any loops in the above.Gresham
@Gresham Assuming you meant : this(, the constructor of Foo calls itself, forming a cycle. This results in a compiler error.Jellyfish
@IS4: Ah. I've used VB.NET much more than C#, though it's been awhile since I've looked much at either; the constructor semantics are a bit different. I think in C# the effect I was looking for could be accomplished by having an object field initializer which throws an exception, since I think in C# those run before the parent constructor call (whereas in VB.NET they run after).Gresham
@IS4: Alternatively, I think one could simply have a constructor which chains to another constructor, but includes within the chaining call a method that will throw an exception.Gresham
It doesn't matter, it won't compile since you have to call inherited constructors and in this case you can't.Classless

© 2022 - 2024 — McMap. All rights reserved.