对于'char'变量,'int'永远不会等于null

时间:2014-03-10 17:13:30

标签: c# variables char int compiler-warnings

有人可以回答我这个问题 - 为什么我会收到这个警告“表达式的结果总是'false',因为'int'类型的值永远不会等于'int'类型的'null'”

这是代码

    private char classLetter;
    public char ClassLetter
    {
        get { return classLetter; }
        set 
        {
            if (classLetter == null)
            {
                classLetter = value;
                RaisePropertyChanged("ClassLetter");
            }
            else throw new ArgumentOutOfRangeException();
        }
    }

如果我使用此代码,则不会出现警告

    private char classLetter;
    public char ClassLetter
    {
        get { return classLetter; }
        set 
        {
            if (classLetter.ToString() == null)
            {
                classLetter = value;
                RaisePropertyChanged("ClassLetter");
            }
            else throw new ArgumentOutOfRangeException();
        }
    }

简而言之,我的问题是这个

如何为char变量提供int警告?

编辑:'char'应该包含任何拉丁语或西里尔字母,没有特殊符号,也不允许使用数字。该如何过滤?

4 个答案:

答案 0 :(得分:4)

类型char的变量是值变量,而不是引用变量,因此它永远不会是null。只有参考类型的变量可以是null

答案 1 :(得分:4)

在第一种情况下,classLetter属于char类型,永远不会是null,因为它是值类型;它需要是char?类型。因此,比较classLetter == null没有意义,正如编译器所说的那样。

在第二种情况下,假设classLetter'x'。在执行classLetter.ToString()时,您会获得"x",这可以与null进行比较,因为它现在是引用类型。但同样,这不是您想要的,因为classLetter.ToString()永远不会是null

如果你想要的只允许设置一次值,你可以这样做:

private char? classLetter = null; // make it nullable
public char ClassLetter
{
    get {
        if(classLetter == null) { // if we don't have a value yet
            // do something, like throwing an exception
        }else{ // if we do have a value already
            return classLetter.Value; // here we return char, not char?
        }
    }
    set 
    {
        if (classLetter == null) {
            classLetter = value;
            RaisePropertyChanged("ClassLetter");
        }
        else throw new ArgumentOutOfRangeException();
    }
}

答案 2 :(得分:1)

您收到警告,因为值类型永远不会为null。完整(呃)解释如下。

C#中的char是值类型,永远不能为空。考虑char的目的,即表示Unicode字符。在0x0到0xFFFFFFFF范围内选择平均值null并没有什么好处。 (确实,UTF-16实际上并不包含整个范围,但它可能会在某一天)。

使用范围小得多的东西有点容易理解。考虑byte。它的范围为0 - 255.现在,为了表示null,我们需要选择一种可以存储null的方式。最终会出现一些解决方案:

  • 将信息额外存储到byte以表示null。 Nullable<Byte>这样做。
  • 选择有效byte范围内的值,实际上代表null。您最终需要在整个程序中检查此值。在一个小规模,这是一个非问题,但当你不知道谁将使用你的代码(一个可能的情况),这是你必须记录并希望他们看到的东西。

提供非可空值类型和默认值的实现要简单得多,并提供可以在需要时表示null的值类型的包装器。 .NET使用Nullable<T>类型完成此操作,它是带语言支持的快捷方式(int?byte?等)。

要解决您的代码问题,如果classLetter确实可以是char可以表示的任何值,那么您可以使用:

private char classLetter;
public char ClassLetter
{
    get { return classLetter; }
    set 
    {
        classLetter = value;
        RaisePropertyChanged("ClassLetter");
    }
}

您可以这样做,因为如果编译器尝试对classLetter执行某些操作,则编译时会给用户一个编译时错误。

如果您对classLetter应该代表的内容有其他要求,请更新您的问题,我会更新我的回答。

回应你对另一个答案的评论:“我希望行为简单。我希望能够放置任何符号,但我不希望变量留空”

我们需要解决的唯一问题是“空”究竟意味着什么。在你的背景下,空意味着什么?回答后,您可以在包含classLetter的类型中使用默认初始化将其设置为该值。一个通用的例子:

class Foo {
  private char classLetter;
  public char ClassLetter {
    get { return classLetter; }
    set {
      classLetter = value;
    }
  }

  public Foo(char classLetter = 'A') {
    this.ClassLetter = classLetter;
  }
}

当来电者使用new Foo()时,他们会获得一个Foo个实例Foo.ClassLetter == 'A'。当然,A可以是满足您特定要求的任何合理默认值。

答案 3 :(得分:0)

这是你想要的吗?

private char? classLetter;
public char ClassLetter
{
    get { return classLetter.Value; // this will throw exception, if value hasn't set }
    set 
    {
        if (classLetter != null)
        {
            throw new InvalidOperationException("ClassLetter has been set already.");
        }

        classLetter = value;
        RaisePropertyChanged("ClassLetter");
    }
}

请注意,ArgumentOutOfRangeException不适合这种情况。您不对参数的范围进行任何测试。