2017-06-29 157 views
1
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类,我想,当我创建一个新的节点对象, 才能够做到这一点:空泛型类型C#

Node<E> n = new Node<E>(null, null, null); 

这并不是因为所有类型的工作不能为空。我惊讶的是,当我在Java中尝试类似的东西时,它可以工作。我已经看到了堆栈溢出的一些相关问题,但他们没有给出我想要的结果。我不想使用default(E)

+0

C#允许泛型与原始类型一起使用,而Java只允许引用类型与泛型。所有的引用类型都可以为null,所以它可以在Java中使用。 – 4castle

+1

'Node n = new Node(null,null,null);'你必须提供特定类型才能工作。 – dcg

+2

'我不需要默认(E)'你不是吗?那怎么不*完全*你想要什么? – Servy

回答

6

你需要一个泛型类型约束指出E必须是引用类型:

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

也就是说,除非你还需要E是出于其他原因的值类型。如果是这样的话,你需要牺牲一个要求或另一个要求。

可为空值类型是一个选项:使用原始版本,缺少类型约束(因为Nullable<T>本身就是一个值类型),您可以使用int?。下面的代码编译,我没有约束:

var y = new Node<int?>(null, null, null); 

int?int,但已经很接近了。

2

我惊讶的是当我在Java中尝试类似的东西时,它的工作原理。

这是因为Java的泛型类型与类型擦除,这实际上意味着,他们都是java.lang.Object后代实现。

例如,您不能使用原始文件int作为您的Node的Java类型参数:您不得不使用java.lang.Integer来代替。因此,无论T如何,element都可以被分配null

在C#中,类型参数没有这样的限制:编写Node<int>是完全合法的。但是,element类型为int您不能再编写element = null,这是您看到的错误的根源。

除了default(T)办法,你提到,你可以要求T是引用类型,像这样:

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

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

1

如果我们这样做:

,首先创建一个简单的界面

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

此之后,我们做了一些变化,您的节点

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类里面

Node<E> n = new Node<E>(
       new Maybe<E>(), 
       null, 
       null 
      ); 

没有更多null检查在这一领域

而是这个

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

看我的答案[关于null对象模式](https://stackoverflow.com/questions/11339729/generic-null-object-pattern-in-c-sharp/44789725#44789725) – kogoia

+0

我也建议删除所有null在你的代码,尤其是 作为构造函数或方法中的参数 – kogoia