何时使用非泛型接口作为泛型类型约束

本文关键字:泛型类型 约束 泛型接口 何时使 | 更新日期: 2023-09-27 18:33:17

我正在努力寻找一种使用非泛型接口作为泛型类型约束的场景。下面是一个任意示例,其中非泛型方法 (RideCar2) 比泛型方法 RideCar 更简单。

class Program
{
    static void Main(string[] args)
    {
        var car = new Merc();
        RideCar(car);
        RideCar2(car);
    }
    static void RideCar<T>(T t) where T : ICar
    {
        t.StartEngine();
        t.StopEngine();
    }
    static void RideCar2(ICar car)
    {
        car.StartEngine();
        car.StopEngine();
    }
}
public interface ICar
{
    void StartEngine();
    void StopEngine();
}
public class Merc : ICar
{
    public void StartEngine() { Console.WriteLine("Merc start"); }
    public void StopEngine() { Console.WriteLine("Merc stop"); }
}

很明显,RideCar2是一个更好的实现,因为它的噪音更少。

是否存在用作泛

型类型约束的非泛型接口有意义的方案?

更多例子(根据答复)

  1. 用作返回类型

static T RideCar(T t) where T : ICar
{
    t.StartEngine();
    t.StopEngine();
    return t;
}

使用普通方法仍然会使泛型方法的使用毫无用处,请参见下文:


static ICar RideCar(ICar car)
{
 car.StartEngine();
 car.StopEngine();
 return car;
}
  1. 多个接口

static void RideCar(T t) where T : ICar, ICanTimeTravel
{
    t.StartEngine();      // ICar
    t.TravelToYear(1955); // ICanTimeTravel
    t.StopEngine();       // ICar
}

使用具有多个参数的普通方法仍然会使泛型方法的使用毫无用处,请参见下文:


static void RideCar(ICar car, ICanTimeTravel canTimeTravel)
{
 car.StartEngine();
 canTimeTravel.TravelToYear(1955);
 car.StopEngine();
}

何时使用非泛型接口作为泛型类型约束

是的,有。考虑:

static T RideCar<T>(T t) where T : ICar
{
    t.StartEngine();
    t.StopEngine();
    return t;
}

这将返回特定类型。现在,您可以使用实现细节,而不必将其转换回实现类型,这是不好的做法。

此外,您可以对同一泛型参数具有多个接口约束:

static void RideCar<T>(T t) where T : ICar, ICanTimeTravel
{
    t.StartEngine();      // ICar
    t.TravelToYear(1955); // ICanTimeTravel
    t.StopEngine();       // ICar
}

最后,即使这有时被认为是代码异味,您也可以将new()约束与接口约束一起使用,以便在方法中创建实现类型的实例:

static T Create<T>() where T : ICar, new()
{
    T t = new T();
    return t;
}

这取决于。在您的情况下,非通用方式是首选。

如果要调用在不同接口上声明的方法,则使用类型约束的泛型声明是有意义的:

public void Test<T>(T value, T other) 
    where T: IEquatable<T>, IComparable<T>
{
    value.Equals(other); //in IEquatable<T>
    value.CompareTo(other); //in IComparable<T>
}

但在这种情况下,如果可能的话,我更喜欢使用基类,并在以下方法中使用它,没有任何类型约束:

public class BaseCar<T> : IEquatable<T>, IComparable<T>, ICar
{
    /// [...]
}
public void Test<T>(BaseCar<T> car1, BaseCar<T> car2)
    where T: IEquatable<T>, IComparable<T>
{
    car1.Equals(car2);
    car1.CompareTo(car2);
}

或没有泛型,但仅限于 ICar:

public class BaseCar : IEquatable<ICar>, IComparable<ICar>
{
    /// [...]
}
public void Test(BaseCar car1, BaseCar car2)
{
    car1.Equals(car2);
    car2.CompareTo(car2);
}