空泛型类型 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 中尝试类似的事情时,它可以工作!我已经在堆栈溢出上看到了一些相关问题,但它们没有给出我想要的结果。我不想使用default(E).

您需要一个泛型类型约束,说明E必须是引用类型:

public class Node<E> : IPosition<E> where E : class

也就是说,除非您出于其他原因还需要E成为值类型。如果是这种情况,您需要牺牲一个或另一个要求。

可为 null 的值类型是一个选项:对于原始版本,缺少类型约束(因为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如何,都可以null分配element

在 C# 中,类型参数没有这样的限制:编写Node<int>是完全合法的。但是,使用类型为intelement,您将无法再写入element = null,这是您看到的错误的根本原因。

除了您提到的default(T)方法之外,您还可以要求T是引用类型,如下所示:

public class Node<E> : IPosition<E> where E : class {
...
}

现在将null传递给Node构造函数的初始参数是合法的,但是使用任何值类型(包括Nullable<Tx>)实例化Node<T>都是非法的。

如果我们这样做怎么办:

首先创建一个简单的界面

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

相关内容

  • 没有找到相关文章