[英]How to implement a generics interface without specific types?
給定這樣的接口:
public interface Transformer<TSource, TResult> {
TResult Transform(TSource original);
}
我想為不需要轉換的情況提供一個簡單的“ no-op”接口實現,它只返回原始對象本身。 在這種情況下, TSource
和TResult
將相同。
作為一個仍在學習C#的Java老兄,我的第一個想法就是:
public class NoopTransformer : Transformer<object, object> {
public override object Transform(object original) {
return original;
}
}
可以編譯,但是我幾乎不能在只需要Transformer
地方使用它。 如果嘗試,會出現編譯錯誤,指出NoopTransformer
不能用作Transformer<TSource, TResult>
我渴望的是Java的通配符或願意將Object
視為任何對象的可接受類型參數。 C#中真的沒有等效功能嗎?
然后我認為這會起作用:
public class NoopTransformer<TSource> : Transformer<TSource, TSource> {
public override TSource Transform(TSource original) {
return entity;
}
}
在任何需要Transformer<TSource, TResult>
地方都無法使用,像這樣:
public class Controller<TEntity, TResult> {
private Transformer<TEntity, TResult> transformer;
public Controller() : this(new NoopTransformer<TEntity>()) // error on this line
{ }
public Controller(Transformer<TEntity, TResult> transformer) {
this.transformer = transformer;
}
}
無法編譯,說:
NoopTransformer<TEntity>
Transformer<TSource, TResult>
為Transformer<TSource, TResult>
NoopTransformer<TEntity>
不可分配給參數類型Transformer<TEntity, TResult>
(即使似乎我的隱含滿足了該約定TSource
和TResult
相同的事實也沒有關系)。
最后,我抓住稻草,嘗試了一下:
public class NoopTransformer<TSource, TResult> : Transformer<TSource, TResult>
where TResult : TSource
{
public override TResult Transform(TSource original) {
return (TResult)entity;
}
}
但是當然這是行不通的,因為我想在哪里使用它,沒有約束說TResult
必須擴展TSource
。
上下文是我有另一個具有相同TSource
和TResult
類型參數的類,並且可以在其構造函數中接受Transformer
。 但是,在該類中,變壓器是可選的。 在客戶端未指定更特定的Transformer
情況下,我想使用NoopTransformer
。
在Java中,這很簡單,實際上有兩種不同的解決方法(使用類型通配符, extends
等)。 我意識到Java更為寬容(由於使用了類型擦除),因此固有地更加靈活,因為在運行時沒有類型參數。 但是,似乎C#編譯器過於嚴格(也許有些愚蠢)。
如何實現為接口提供有用的默認值的目標?
編譯器正確拒絕
public Controller() : this(new NoopTransformer<TEntity>())
由於Transformer<TEntity, TEntity>
與Transformer<TEntity, TResult>
不兼容,因為不能保證TEntity
和TResult
是相同的,例如
var c = new Controller<string, int>();
您可以通過創建工廠方法來構造TEntity
和TResult
相同的Controller
實例來維護靜態安全性:
public static class Controller
{
public static Controller<TEntity, TEntity> Create<TEntity>()
{
return new Controller<TEntity, TEntity>(new IdentityTransformer<TEntity>());
}
}
如果由於某種原因您不能采用這種方法,則必須在運行時依賴轉換:
public class CastingTransformer<TSource, TResult> : Transformer<TSource, TResult>
{
public TResult Transform(TSource original)
{
return (TResult)(object)original;
}
}
public Controller() : this(new CastingTransformer<TEntity, TResult>()) { }
這就是您的想法嗎?
public interface Transformer<TSource, TResult>
{
TResult Transform(TSource original);
}
public class NoopTransformer<TSource, TResult> : Transformer<TSource, TResult> where TResult : class
{
public TResult Transform(TSource original)
{
return original as TResult;
}
}
public class Controller<TEntity, TResult> where TResult : class
{
private Transformer<TEntity, TResult> transformer;
public Controller() : this(new NoopTransformer<TEntity, TResult>())
{ }
public Controller(Transformer<TEntity, TResult> transformer)
{
this.transformer = transformer;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.