首页 > 解决方案 > 第二个通用参数的推断

问题描述

我有如下的类结构:


public interface IBinder<T>
    where T : Control
{
    T Control { get; }
}

public class ButtonBinder : IBinder<Button>
{
    public ButtonBinder(Button control)
    {
        Control = control ?? throw new ArgumentNullException(nameof(control));
    }

    public Button Control { get; private set; }
}

在这样的工厂方法的帮助下创建我想要的那个 Binder 的实例:

public void Main()
{
    // This line works.
    var binder = RegisterBinder<ButtonBinder, Button>(new Button());

    // But I want use type inference like this:
    var binder2 = RegisterBinder<ButtonBinder>(new Button());
}

/// <summary>
/// My pseudo-factory.
/// </summary>
public T_Binder RegisterBinder<T_Binder, T_Control>(T_Control control)
    where T_Binder : IBinder<T_Control>
    where T_Control : Control
{
    return (T_Binder)Activator.CreateInstance(typeof(T_Binder), control);
}

因为“ButtonBinder”类声明了通用控件类型“Button”,编译器应该能够推断出它。我如何告诉编译器我想使用类型推断?

谢谢你。

标签: c#.netgenericstype-inference

解决方案


不幸的是,C# 不能仅推断多个泛型参数之一。但是,如果您不介意在中间类中捕获可推断类型,则可以执行以下操作:

public class Factory
{
    public void Main()
    {
        // This line works.
        var binder = RegisterBinder<ButtonBinder, Button>(new Button());

        // Now only T_Binder is needed
        var binder2 = ForControl(new Button()).RegisterBinder<ButtonBinder>();
    }

    private BinderRegistration<T_Control> ForControl<T_Control>(T_Control control) where T_Control : Control
    {
        return new BinderRegistration<T_Control>(control);
    }

    /// <summary>
    /// My pseudo-factory.
    /// </summary>
    public T_Binder RegisterBinder<T_Binder, T_Control>(T_Control control)
        where T_Binder : IBinder<T_Control>
        where T_Control : Control
    {
        return (T_Binder)Activator.CreateInstance(typeof(T_Binder), control);
    }
}

internal class BinderRegistration<T_Control>
    where T_Control : Control
{
    private readonly Control _control;

    public BinderRegistration(Control control)
    {
        _control = control;
    }

    public T_Binder RegisterBinder<T_Binder>() 
        where T_Binder : IBinder<T_Control>
    {
        return (T_Binder)Activator.CreateInstance(typeof(T_Binder), _control);
    }
}

推荐阅读