将类型变量转换为通用参数

时间:2019-01-09 10:13:58

标签: c#

目前我有此方法

    public void HandleComponent<T>() where T : IComponent
    {
        // do something with T
    }

我想拥有一个方法HandleComponents,在其中我可以传递多个泛型类型,并且该方法遍历它们并调用HandleComponent<currentGenericType>

我知道不可能有可变数量的通用参数,但是如何为该问题创建解决方法?我开始创建这个

    public void HandleComponents(Type[] components)
    {
        for (int i = 0; i < components.Length; i++)
        {
            HandleComponent<components[i]>(); // This is not possible
        }
    }
  1. components[i]需要进行转换,因为当前这不是通用参数

  2. 我必须确保每个Type参数都实现IComponent。我知道我可以在方法中进行检查,但是我想防止传入无效的参数。因此该方法必须看起来像(伪代码)

    public void HandleComponents(Type[] components) where components : IComponent
    {
        for (int i = 0; i < components.Length; i++)
        {
            HandleComponent<components[i]>();
        }
    }
    

    这是不可能的,对吧?

完美的解决方案看起来像这样

public void HandleComponents<AListOfGenericTypes>() where EachGenericListItem : IComponent
{
    for (int i = 0; i < AListOfGenericTypes.Count; i++)
    {
        HandleComponent<AListOfGenericTypes[i]>();
    }
}

4 个答案:

答案 0 :(得分:1)

如何使用params

class Program
{
    static void Main(string[] args)
    {
        IComponent cp1 = new Component1();//Created here or elsewhere
        IComponent cp2 = new Component2();//Created here or elsewhere
        IComponent cp3 = new Component3();//Created here or elsewhere

        HandleComponents<IComponent>(cp1, cp2, cp3);
    }

    private static void HandleComponents<T>(params T[] components) where T : IComponent
    {
        foreach (T component in components)
        {
            HandleComponent(component);
        }
    }

    private static void HandleComponent<T>(T component) where T : IComponent
    {
       //Do whatever with T
    }
}

public class Component1 : IComponent { }

public class Component2 : IComponent { }

public class Component3 : IComponent { }

public interface IComponent { }

答案 1 :(得分:1)

没有反思就不可能。我建议您重写方法HandleComponent

public void HandleComponent(Type objectType)
{
    // do something with T
}

您可以致电:

public void HandleComponents(Type[] components)
{
    for (int i = 0; i < components.Length; i++)
    {
        HandleComponent(components[i]);
    }
}

反射解决方案:

public void HandleComponents(Type[] components)
{
    var method = this.GetType().GetMethod("HandleComponent");
    for (int i = 0; i < components.Length; i++)
    {
        method.MakeGenericMethod(components[i])
            .Invoke(this, null);
    }
}

答案 2 :(得分:1)

如果您想这样做,并且可以接受可以传递的实际组件数量上限,请从const currentUrl = this.location.path(); const displayTile = currentUrl.includes('/search-resources') || currentUrl.includes('/calendar') || currentUrl.includes('/yearbooks')? 1 : 2; ,{{1} }和Func系列类型,并让您的复制和粘贴手指热身:

Action

这是不理想的,而且就像我说的那样,它对一个调用可以传递多少个组件施加了上限。因为每个调用都必须分别进行参数设置,所以这里无法使用循环。


或者:

Tuple

这里是text template,可减少复制和粘贴(并更可重用于其他方法):

public void HandleComponent<T>(T component) where T : IComponent { //Real logic } public void HandleComponents<T1, T2>(T1 component1, T2 component2) where T1 : IComponent where T2 : IComponent { HandleComponent(component1); HandleComponent(component2); } public void HandleComponents<T1, T2, T3>(T1 component1, T2 component2, T3 component3) where T1 : IComponent where T2 : IComponent where T3 : IComponent { HandleComponent(component1); HandleComponent(component2); HandleComponent(component3); } 作为文本模板添加到您的项目中,然后为其提供以下内容:

public void HandleComponent<T>() where T : IComponent
{
    //Real logic
}

public void HandleComponents<T1, T2>()
    where T1 : IComponent
    where T2 : IComponent
{
    HandleComponent<T1>();
    HandleComponent<T2>();
}
public void HandleComponents<T1, T2, T3>()
    where T1 : IComponent
    where T2 : IComponent
    where T3 : IComponent
{
    HandleComponent<T1>();
    HandleComponent<T2>();
    HandleComponent<T3>();
}

(您将要针对这些方法应进入的类编辑第8行,并确保在其他位置将其标记为局部。也请针对名称空间进行调整)

答案 3 :(得分:1)

我认为不可能完全实现您想要的目标,但是您可以通过使用反射和MakeGenericMethod来获取通用的HandleComponent方法并使用传递给HandleComponents方法的类型来调用它来克服这个问题,只是传入类型的过滤必须在for循环中进行,而不必通过通用约束,因为该方法没有通用的方法。

class Program
{
    public interface IComponent { }
    public class ComponentA : IComponent { }
    public class ComponentB : IComponent { }

    static void Main(string[] args)
    {
        HandleComponents(new[] { typeof(ComponentB), typeof(ComponentA) });
        Console.ReadKey();
    }

    private static void HandleComponent<T>()
        where T : IComponent
    {
        Console.WriteLine(typeof(T));
    }

    private static void HandleComponents(Type[] components)
    {
        var m = typeof(Program).GetMethod("HandleComponent", BindingFlags.NonPublic | BindingFlags.Static);
        foreach (var component in components)
        {
            if (typeof(IComponent).IsAssignableFrom(component))
            {
                var genericMethod = m.MakeGenericMethod(component);
                genericMethod.Invoke(null, null);
            }
        }
    }
}