Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Statically define a member using the dynamically determined class type

I'm trying to create an event delegate where the parameter is strongly typed to match the current class, like this:

public class HPCRequest
{
    public delegate void RequestCompleteHandler(HPCRequest request);
    public event RequestCompleteHandler RequestComplete;

The problem is that the point of this class is to be inherited, and what I really want is for all those inheriting classes to have the "RequestComplete" event, where the delegate is typed for that class:

public class HPCGetConfig : HPCRequest
{
    //I want this class to effectively inherit something like this:
    //public delegate void RequestCompleteHandler(HPCGetConfig request);

This is because currently, when I have a function that handles one of my "RequestComplete" events, I currently have to do this:

    myGetConfigRequest.RequestComplete += new HPCRequest.RequestCompleteHandler(HPCGetExpectedLosses_RequestComplete);

void HPCGetConfig_RequestComplete(HPCRequest request)
{
    HPCGetConfig thisRequest = request as HPCGetConfig;
    //This should be strongly typed in the first place.

But I want to be able to do something like this:

    request.RequestComplete += new HPCGetConfig.RequestCompleteHandler(HPCGetConfig_RequestComplete);
    request.SendRequestAsync();
}

void HPCGetConfig_RequestComplete(HPCGetConfig request)
{
    request.RequestComplete -= HPCGetConfig_RequestComplete;

Attempts

I've tried this:

public delegate void RequestCompleteHandler<T>(T request) where T : HPCRequest; 
public event RequestCompleteHandler<T> RequestComplete;

but when I try to invoke the event from within the base class using RequestComplete(this);, I get a compile time error: `Delegate 'RequestCompleteHandler' has some invalid arguments.

This happens whether or not I set up the entire HPCRequest class as HPCRequest<T> by going:

public class HPCRequest<T> where T : HPCRequest<T> 
{
    public delegate void RequestCompleteHandler<T>(T request); 
    public event RequestCompleteHandler<T> RequestComplete;

public class HPCGetConfig : HPCRequest<HPCGetConfig> { ...

The same error occurs when I try to invoke the event: RequestComplete(this);

 

I've also tried all forms of creating the delegate and event and overriding them, such as in doing:

public class HPCRequest
{
    public delegate void RequestCompleteHandler(HPCRequest request);
    public virtual event RequestCompleteHandler RequestComplete;


public sealed class HPCGetConfig : HPCRequest
{
    public delegate void RequestCompleteHandler(HPCGetConfig request);
    public override event RequestCompleteHandler RequestComplete;

But this gives me a compile time error because I cannot override the RequestComplete event with one of a different delegate type.

Any other ideas?


Edit

Templating the entire HPCRequest class is not an option, after a very thorough attempt, I see that it just screws up every attempt to use the type HPCRequest as a placeholder for any request type. If this solution is going to work, the class HPCRequest must be able to be instantiated and inherited from without specifying a type parameter. I'll need a solution that doesn't require templating HPCRequest.

To make sure everyone know exactly how I'm trying to use this, I pasted some sample code into pastebin that should let you experiment with ways of getting this event templating working without breaking anything. Here it is: http://pastebin.com/bbEYgLj1

like image 954
Alain Avatar asked Feb 23 '23 12:02

Alain


1 Answers

What you could try:

public abstract class HPCRequest<T> where T : HPCRequest<T>
{
  public delegate void RequestCompleteHandler(T request);
  public event RequestCompleteHandler RequestComplete;

  protected void RaiseRequestComplete(T request)
  {
    if (RequestComplete != null)
    {
      RequestComplete(request);
    }
  }
}

public class Foo : HPCRequest<Foo>
{
  public void Bar()
  {
    RaiseRequestComplete(this);
  }
}

public class Example
{
  public static void Test()
  {
    var request = new Foo();

    request.RequestComplete += RequestComplete;
  }

  static void RequestComplete(Foo request)
  {
    // It's a Foo!
  }
}

This self-referential generic constraint allows what you want I think. I added the protected RaiseRequestCompleted so you can still raise the event from classes that inherit from HCPRequest. Otherwise, only HCPRequest would be allowed to do so.

UPDATE: I updated the code to pass this and added sample code that matches your desired result.

like image 135
JulianR Avatar answered Apr 28 '23 08:04

JulianR