Swift泛型Protocol对比C#泛型Interface
本篇純屬抬杠之作,之前我們提到了Swift的泛型Protocol使用associatedtype關鍵字,而不是使用<Type>語法的泛型參數。這其中有什么好處呢?
我就這個問題搜索了一些回答,大體上提到兩點:
<Type>語法對Protocol沒有意義,Protocol僅需要定義一個抽象的概念,具體的類型應該由實現的Class來明確,比如:
ClassWithInt<Int>: NumberProtocol ClassWithDouble<Double>: NumberProtocolassociatedtype可以用來給Protocol中特定Func添加泛型約束,而不是限定整個Protocol
protocol GeneratorType {associatedtype Elementpublic mutating func next() -> Self.Element? }聽上去還是有一定道理的,然后實踐是檢驗事實的唯一標準。下面我們通過代碼實例來和C#進行對比。首先拿出網上多被引用解釋上述兩個觀點的Swift代碼:
public protocol Automobile {associatedtype FuelTypeassociatedtype ExhaustTypefunc drive(fuel: FuelType) -> ExhaustType } public protocol Fuel {associatedtype ExhaustTypefunc consume() -> ExhaustType } public protocol Exhaust {init()func emit() }public struct UnleadedGasoline<E: Exhaust>: Fuel {public func consume() -> E {print("...consuming unleaded gas...")return E()} } public struct CleanExhaust: Exhaust {public init() {}public func emit() {print("...this is some clean exhaust...")} } public class Car<F: Fuel,E: Exhaust>: Automobile where F.ExhaustType == E {public func drive(fuel: F) -> E {return fuel.consume()} }public class Car1<F: Fuel>: Automobile {public func drive(fuel: F) -> F.ExhaustType {return fuel.consume()} }具體的使用情況如下:
var car = Car<UnleadedGasoline<CleanExhaust>, CleanExhaust>() car.drive(fuel: UnleadedGasoline<CleanExhaust>()).emit()var fusion = Car1<UnleadedGasoline<CleanExhaust>>() fusion.drive(fuel: UnleadedGasoline<CleanExhaust>()).emit()轉換成C#代碼的話,有兩種思路,首先是把泛型參數放到Interface層面:
public interface Automobile<FuelType, ExhaustType>{ExhaustType Drive(FuelType fuel);}public interface Fuel<ExhaustType>{ExhaustType consume();}public interface Exhaust {void Emit();}public class UnleadedGasoline<Exhaust> : Fuel<Exhaust> where Exhaust : new(){public Exhaust consume(){Console.WriteLine("...consuming unleaded gas...");return new Exhaust();}}public class CleanExhaust : Exhaust{public void Emit(){Console.WriteLine("...this is some clean exhaust...");}}public class Car : Automobile<UnleadedGasoline<CleanExhaust>, CleanExhaust>{public CleanExhaust Drive(UnleadedGasoline<CleanExhaust> fuel){return fuel.consume();}}還可以模仿Swift對Automobile多做一層繼承進行包裝:
public interface Car1<T1> : Automobile<UnleadedGasoline<T1>, T1> where T1 : new(){}public class SimpleCar : Car1<CleanExhaust>{public CleanExhaust Drive(UnleadedGasoline<CleanExhaust> fuel){return fuel.consume();}}調用的時候沒有什么太大的差別:
var gaso = new UnleadedGasoline<CleanExhaust>(); var car = new Car();car.Drive(gaso).Emit(); var simpleCar = new SimpleCar();simpleCar.Drive(gaso).Emit();和Swift比較不同的是,我們在Interface就代入了泛型參數。但是由于我們不能直接實例化Interface,所以并不能直接使用Automobile來減少一層繼承關系。
因為上述提到的使用associatedtype 的第一點理由見仁見智,這里不分高下。
C#還有第二種思路,就是我也把泛型約束下放到Func層級:
public interface Automobile{ExhaustType Drive<FuelType,ExhaustType>(FuelType fuel) where ExhaustType : new();}public interface Fuel{ExhaustType consume<ExhaustType>() where ExhaustType : new();}public class UnleadedGasoline : Fuel{public Exhaust consume<Exhaust>() where Exhaust : new(){Console.WriteLine("...consuming unleaded gas...");return new Exhaust();}}public class Car2 : Automobile{public CleanExhaust Drive<UnleadedGasoline, CleanExhaust>(UnleadedGasoline fuel) where CleanExhaust : new(){return (fuel as Fuel).consume<CleanExhaust>();}}C#的接口并不能定義構造函數。強行模仿起來還真是有點累啊。最終的使用也很簡單:
var fuel = new UnleadedGasoline();var car2 = new Car2();car2.Drive<UnleadedGasoline,CleanExhaust>(fuel).Emit();通篇比較下來,應該說Swift通過associatedtype 關鍵字和<Type>的混用,使得泛型的定義更為復雜也更靈活了。
GitHub:
https://github.com/manupstairs/LearnSwift
https://github.com/manupstairs/LearnDotNetCore
?
?
轉載于:https://www.cnblogs.com/manupstairs/p/5980850.html
總結
以上是生活随笔為你收集整理的Swift泛型Protocol对比C#泛型Interface的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: p系列服务器产品介绍,常用p系列服务器R
- 下一篇: ABAP ALV