简体   繁体   English

具有嵌套泛型类型的方法

[英]Method with nested generic types

I have something along the lines: 我有一些思路:

public class BaseClass
{

}

public class SimpleDerivedA : BaseClass
{
    public void DoSomething() => Expression.Empty();        
}

public class SimpleDerivedB : BaseClass
{
    public void DoSomething() => Expression.Empty();          
}

public class GenericDerived<T> : BaseClass where T : struct
{
    public T data;
    public void DoSomething<T>(T someParameter) => Expression.Empty();        
}

public void Process<T, X>(T someObject, X someValue = default) where T : BaseClass where X : struct
{
    switch (someObject)
    {
        case SimpleDerivedA a:
            a.DoSomething();
            break;
        case SimpleDerivedB b:
            b.DoSomething();
            break;
        case GenericDerived<X> g:
            X obj = new X();
            g.DoSomething(obj);
            break;
    }

}

Process method works in an ugly way: 处理方法的工作方式很丑陋:

    SimpleDerivedA a = new SimpleDerivedA();
    SimpleDerivedB b = new SimpleDerivedB();
    GenericDerived<Vector3> g = new GenericDerived<Vector3>();

    Process(a, new int()); //second parameter is fake, just to be able to 
    call the method
    Process(b, new int()); //second parameter is fake, just to be able to 
    call the method
    Process(g, new Vector3());//second parameter is fake, just to be able to 
    call the method

Ideally I should be able to call Process(a), Process(b), Process(g) 理想情况下,我应该能够调用Process(a),Process(b),Process(g)

Something like: 就像是:

public void Process<T>(T someObject)  where T: BaseClass where X: struct
    {
        switch (someObject)
        {
            case SimpleDerivedA a:
                a.DoSomething();
                break;
            case SimpleDerivedB b:
                b.DoSomething();
                break;
            case GenericDerived<X> g:
                var obj = new X();
                g.DoSomething(obj);
                break;
        }

    }

or: 要么:

public void Process<T<X>>(T someObject) where T : BaseClass where X : struct
    {
        switch (someObject)
        {
            case SimpleDerivedA a:
                a.DoSomething();
                break;
            case SimpleDerivedB b:
                b.DoSomething();
                break;
            case GenericDerived<X> g:
                var obj = new X();
                g.DoSomething(obj);
                break;
        }

    }

Which obviously don't compile. 显然不编译。 I need to use it inside an API and the type of GenericDerived<T> won't be known until someone will use it. 我需要在API中使用它,直到有人使用它,才能知道GenericDerived<T>的类型。

The question here is how can I define the method Process so I can use an instance of any of the three derived classes as a parameter but call it only with one parameter like Process(value) not Process(value, fakeValue) or Process<SomeType>(value) ? 这里的问题是如何定义方法Process,以便可以使用三个派生类中的任何一个的实例作为参数,但只能使用一个参数(例如Process(value)而不是Process(value, fakeValue)Process<SomeType>(value) Process(value, fakeValue)调用它Process<SomeType>(value)

Add interface to the base class. 将接口添加到基类。

interface IProcessable
{
    void DoSomething(params object [] args);
}

public abstract class BaseClass : IProcessable
{
    public abstract void DoSomething(params object[] args);
}

public class GenericDerived<T> : BaseClass where T : struct
{
    public T data;
    public override void DoSomething(params object[] args)
    {
        // optionally you can pass as many arguments as you like
        data = (T)args.First();
    }
}

And then you can pass your object into method like this. 然后,您可以将对象传递给这样的方法。

public static void Process(IProcessable obj, params object[] args)
{
    obj.DoSomething(args);
}

Then call it from where ever you need like this 然后从任何需要的地方调用它

var a =  new SimpleDerivedA();
var b = new SimpleDerivedB();
var c = new GenericDerived<T>();
Process(a);
Process(b);
Process(c, obj /* your struct T */);
public interface IGenericDoSomething
{
  void DoSomethingWithDefault();
}

public class GenericDerived<T> : BaseClass, IGenericDoSomething where T : struct
{
  public T data;
  public void DoSomething<X>(X someParameter) => Console.WriteLine(someParameter);

  void IGenericDoSomething.DoSomethingWithDefault() => DoSomething(default(T)); 
}

  public void Process<T>(T someObject) where T : BaseClass {
    switch (someObject)
    {
      case SimpleDerivedA a:
        a.DoSomething();
        break;
      case SimpleDerivedB b:
        b.DoSomething();
        break;
      case IGenericDoSomething g:
        g.DoSomethingWithDefault();
        break;
    }
  }

You should use an overload of your Process function for objects of type GenericDerived , instead of trying to handle everything in one function. 您应该对GenericDerived类型的对象使用Process函数的重载,而不是尝试在一个函数中处理所有事情。

void Process<T>(T someObject) where T : BaseClass {
    switch (someObject)
    {
        case SimpleDerivedA a:
            a.DoSomething();
            break;
        case SimpleDerivedB b:
            b.DoSomething();
            break;
    }
}

void Process<X>(GenericDerived<X> g) where X : struct {
    X obj = new X();
    g.DoSomething(obj);
}

You can then call it like this. 然后可以这样称呼它。

var a = new SimpleDerivedA();
var b = new SimpleDerivedB();
var g = new GenericDerived<Vector3>();

Process(a);
Process(b);
Process(g);

Also consider introducing an interface for objects that can DoSomething , or add a virtual method to BaseClass , so you don't have to type-switch just to call the same method on different objects. 还可以考虑为可以执行DoSomething对象引入接口,或者向BaseClass添加虚拟方法,因此您不必为了在不同对象上调用相同方法而进行类型切换。 This might not be possible since there's a parameter in some derived classes but not others. 这可能是不可能的,因为在某些派生类中有一个参数,而在另一些类中则没有。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM