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

时间:2016-02-05 07:38:51

标签: c# generics interface

我正在努力寻找一种将非泛型接口用作泛型类型约束的方案。下面是一个任意的例子,其中非泛型方法(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. 使用返回类型
  2. 
    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. 多个界面
    2. 
      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();
      }
      

2 个答案:

答案 0 :(得分:5)

是的,有。考虑:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<img id="image" src="http://i.stack.imgur.com/gTiMi.png" usemap="#Map" >
    <map name="Map">
    <area data-number="1" class="area" shape="rect" coords="5,5,35,30" href="#">
    <area data-number="2" class="area" shape="rect" coords="50,5,75,30" href="#">
    <area data-number="9" class="area" shape="rect" coords="90,5,115,30" href="#">
    <area data-number="7" class="area" shape="rect" coords="130,5,155,30" href="#">
    <area data-number="3" class="area" shape="rect" coords="170,5,195,30" href="#">
    
    <area data-number="0" class="area" shape="rect" coords="5,50,35,75" href="#">
    <area data-number="5" class="area" shape="rect" coords="50,50,75,75" href="#">
    <area data-number="4" class="area" shape="rect" coords="90,50,115,75" href="#">
    <area data-number="8" class="area" shape="rect" coords="130,50,155,75" href="#">
    <area data-number="6" class="area" shape="rect" coords="170,50,195,75" href="#">
</map>

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

此外,您可以对同一个通用参数设置多个接口约束:

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()

答案 1 :(得分:0)

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

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

[Row(id_sa=a1, max_id_sb=b2),
 Row(id_sa=a2, max_id_sb=b2)]

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

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>
}

或没有泛型,但限于ICar:

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);
}