簡體   English   中英

何時使用非通用接口作為通用類型約束

[英]When to use a non-generic interface as a generic type constraint

我正在努力尋找一種使用非通用接口作為通用類型約束的方案。 下面是一個任意示例,其中非泛型方法(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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM