[英]Null generic type c#
public class Node<E> : IPosition<E>
{
private E element;
public Node<E> PrevNode { get; set; }
public Node<E> NextNode { get; set; }
//Constructor
public Node(E e, Node<E> p, Node<E> n)
{
element = e;
PrevNode = p;
NextNode = n;
}
}
當我創建一個新的節點對象時,我有我想要的上述Node
類,以便能夠做到這一點:
Node<E> n = new Node<E>(null, null, null);
這不起作用,因為在 C# 中所有類型都不能為 null。 令我驚訝的是,當我在 Java 中嘗試類似的事情時,它起作用了! 我在 Stack Overflow 上看到了一些相關的問題,但他們沒有給出我想要的結果。 我不想使用default(E)
。
您需要一個泛型類型約束,聲明E
必須是引用類型:
public class Node<E> : IPosition<E> where E : class
也就是說,除非出於其他原因還需要E
成為值類型。 如果是這種情況,您需要犧牲一個或另一個要求。
可空值類型是一種選擇:對於您的原始版本,缺少類型約束(因為Nullable<T>
本身就是值類型),您可以使用int?
. 以下代碼在沒有約束的情況下為我編譯:
var y = new Node<int?>(null, null, null);
int?
不是int
,但也不完全不是int
,是嗎?
令我驚訝的是,當我在 Java 中嘗試類似的東西時,它確實有效。
這是因為 Java 泛型類型是通過類型擦除實現的,這實際上意味着它們都是java.lang.Object
后代。
例如,您不能在 Java 中使用原始int
作為Node
的類型參數:您被迫使用java.lang.Integer
代替。 因此,無論T
是什么, element
都可以被賦值為null
。
在 C# 中,類型參數沒有這樣的限制:編寫Node<int>
是完全合法的。 但是,對於int
類型的element
,您不能再編寫element = null
,這是您看到的錯誤的根本原因。
除了您提到的default(T)
方法之外,您還可以要求T
是引用類型,如下所示:
public class Node<E> : IPosition<E> where E : class {
...
}
現在將null
傳遞給Node
構造函數的初始參數是合法的,但是使用任何值類型實例化Node<T>
是非法的,包括Nullable<Tx>
。
如果我們這樣做怎么辦:
首先創建一個簡單的界面
public interface IOptional<T>: IEnumerable<T> {}
並編寫它的實現
public class Maybe<T>: IOptional<T>
{
private readonly IEnumerable<T> _element;
public Maybe(T element)
: this(new T[1] { element })
{}
public Maybe()
: this(new T[0])
{}
private Maybe(T[] element)
{
_element = element;
}
public IEnumerator<T> GetEnumerator()
{
return _element.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
在此之后,我們對您的 Node 類進行了一些更改
public class Node<E> : IPosition<E>
{
private IOptional<E> element;
public Node<E> PrevNode { get; set; }
public Node<E> NextNode { get; set; }
//Constructor
public Node(IOptional<E> e, Node<E> p, Node<E> n)
{
element = e;
PrevNode = p;
NextNode = n;
}
}
並使用它
Node<E> n = new Node<E>(
new Maybe<E>(),
null,
null
);
此字段上的 Node 類中不再有空檢查
而不是這個
if (this.element != null) { .. }
像這樣寫
this.element.Select(e => { doSomething(e); return true; })
像這樣
if (this.element.Any())
{
var elem = this.element.First();
// do something
}
或者寫一個小的擴展方法
public static IOptional<TOutput> Match<TInput, TOutput>(
this IEnumerable<TInput> maybe,
Func<TInput, TOutput> some, Func<TOutput> nothing)
{
if (maybe.Any())
{
return new Maybe<TOutput>(
some(
maybe.First()
)
);
}
else
{
return new Maybe<TOutput>(
nothing()
);
}
}
並且這樣做
var result = this.element
.Match(
some: e => e.ToString(),
nothing: () => "Ups"
)
.First();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.