admin管理员组

文章数量:1379438

I have an interface function called SetParametersAsync(BaseClass myObject), the interface is not mine so I can't change the signature. Inside the function there's an if/else statement which checks the type of the object and invokes methods. Now there's a new type to be added, which is a generic type DerivedClass<T> : BaseClass where T : struct The Type of T is not relevant here, I want to call the same methods on the derived class object for all types of T.
Here's an incomplete example code of what I need:

// existing class, can't alter the signature
public class ExampleClass : IParameterMethods
{
  // inherited from interface, can't alter the signature
  public async Task<bool> SetParametersAsync(BaseClass myObject)
  {
   if (myObject is MyClassA a) 
   {
     a.DoThis();
     MethodThatExpectsAMyClassAParameter(a);
   }
   // ...other ifs
   // NOW THIS IS WHAT I NEED TO ADD FOR THE NEW GENERIC CLASS:
   else if (myObject is DerivedClass<T> derived)
   {
     derived.MethodFromGenericClass();
     MethodThatExpectsDerivedClassTParameter(derived);
   }
  }

  // this is a method I need to call with my generic object, as you can see the exact type of T does not matter, it just has to be a struct type that's all
  private void MethodThatExpectsDerivedClassTParameter(DerivedClass<T> derived) where T: struct
{
  ...
}

Of course the above doesn't compile because T is not known. I don't want to add "ifs" for all possible types of T, so what can I do to solve this problem?

I have an interface function called SetParametersAsync(BaseClass myObject), the interface is not mine so I can't change the signature. Inside the function there's an if/else statement which checks the type of the object and invokes methods. Now there's a new type to be added, which is a generic type DerivedClass<T> : BaseClass where T : struct The Type of T is not relevant here, I want to call the same methods on the derived class object for all types of T.
Here's an incomplete example code of what I need:

// existing class, can't alter the signature
public class ExampleClass : IParameterMethods
{
  // inherited from interface, can't alter the signature
  public async Task<bool> SetParametersAsync(BaseClass myObject)
  {
   if (myObject is MyClassA a) 
   {
     a.DoThis();
     MethodThatExpectsAMyClassAParameter(a);
   }
   // ...other ifs
   // NOW THIS IS WHAT I NEED TO ADD FOR THE NEW GENERIC CLASS:
   else if (myObject is DerivedClass<T> derived)
   {
     derived.MethodFromGenericClass();
     MethodThatExpectsDerivedClassTParameter(derived);
   }
  }

  // this is a method I need to call with my generic object, as you can see the exact type of T does not matter, it just has to be a struct type that's all
  private void MethodThatExpectsDerivedClassTParameter(DerivedClass<T> derived) where T: struct
{
  ...
}

Of course the above doesn't compile because T is not known. I don't want to add "ifs" for all possible types of T, so what can I do to solve this problem?

Share Improve this question edited Mar 20 at 11:15 sth_Weird asked Mar 20 at 11:00 sth_Weirdsth_Weird 6688 silver badges16 bronze badges 8
  • 8 "I want to call the same methods on the derived class object for all types of T" - if T isn't important, then can the method not be in BaseClass? – Jon Skeet Commented Mar 20 at 11:03
  • 5 If your methods are not available on BaseClass you need to define an interfaces without generics that is implemented by DerivedClass<T>. Your if checks for that interface instead of DerivedClass<T>. – Sebastian Schumann Commented Mar 20 at 11:06
  • 1 Is that a typo did you mean where T : struct? What does MethodThatExpectsDerivedClassTParameter actually do? Please give a minimal reproducible example, also with the definition of the base and derived classes. – Charlieface Commented Mar 20 at 11:07
  • 3 IF the methods cannot be in BaseClass, then maybe there needs to be a DerivedClass : BaseClass from which there is DerivedClass<T> : DerivedClass? – Fildor Commented Mar 20 at 11:12
  • 6 If DerivedClass<T> could implement a non-generic interface, and you put the method in that interface, then you'd just need if (myObject is INonGenericInterface x) { x.MethodFromInterface(); }. – Jon Skeet Commented Mar 20 at 11:17
 |  Show 3 more comments

1 Answer 1

Reset to default 0

I don't know if that's what you are looking for, but this is how I would probably tackle this:

Some explanations in comments...

using System;
                    
public class Program : ICallHost
{
    public static void Main()
    {
        var p = new Program();
        var test = new DerivedClass<DateTimeOffset>();
        p.Driver(test);
    }
    
    private void Driver(BaseClass bc)
    {
        // if ... else if ... goes here
        if(bc is DerivedClass dc) // You do not care about T, here.
        {
            dc.ThatOtherMethod();
            // Tell dc to call back
            // We do not have a means without reflection or test every possible T
            // which T dc actually is ...
            dc.CallTheMethod(this);
        }
    }
    
    // You _do_ care about T here
    public void TheMethod<T>(DerivedClass<T> dc) where T : struct
    {
        Console.WriteLine("Hello from {0}", dc.GetType().FullName);
    }
}

// Interfaces for double-dispatch visitor pattern
public interface IVisitor
{
    void CallTheMethod(ICallHost host);
}

public interface ICallHost
{
    void TheMethod<T>(DerivedClass<T> dc) where T : struct;
}

public abstract class BaseClass
{}

// intermediate non-generic derived class to detect the class family
public abstract class DerivedClass : BaseClass, IVisitor
{
// All implementations are abstract here, so DerivedClass<T> has to implement.
// You could add common methods with implementation here, too.
    public abstract void CallTheMethod(ICallHost host);
    public abstract void ThatOtherMethod();
}

public sealed class DerivedClass<T> : DerivedClass where T : struct
{
    // perform the callback passing this instance as concrete generic type
    // because this instance knows what T it is.
    public override void CallTheMethod(ICallHost host) => host.TheMethod(this);

    public override void ThatOtherMethod(){
        Console.WriteLine("That other method.");
    }
}

See it in action : Fiddle

Output:

That other method.
Hello from DerivedClass`1[[System.DateTimeOffset, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]

本文标签: cCast object to MyGenericTypeltTgt when type of T is not importantStack Overflow