• 无法将 NULL 转换成“System.DateTime”,因为它是一种值类型


    摘自:http://www.blogjava.net/parable-myth/archive/2010/09/30/333454.html

    http://blog.csdn.net/seattle1215/article/details/6662896

    关于null

    在C# 2.0里面的数据类型中,分为值类型和引用类型,引用类型可以初始化为null,可是值类型是不可以的。

    C# 允许将 null 值赋给任意引用变量(不能把 null 赋给一个值变量)。值为 null 的变量表明该变量不引用内存中的任何对象。

    比如经常用到的System.Guid类型,要么赋值为Guid.NewId,要么赋值为Guid.Empty。
    再比如System.DateTime,默认初始化为DateTime.MinValue。

    强行给值类型赋null值,编译就不会通过,会报出类似下面的异常:
    错误 1 无法将 NULL 转换成“System.DateTime”,因为它是一种值类型
    这个时候就要借助Nullable<T>结构体了。

    拿DateTime举例,完整的写法:
    Nullable<DateTime> now = DateTime.Now;
    Nullable<DateTime> now = null;
    当然也可以缩写:
    DateTime? now = DateTime.Now;
    DateTime? now = null;

      C# 不允许把 null 赋给一个值类型的数据。在 C# 中,以下语句是非法的:

        int a = null;    // 非法  

    但是,利用 C# 定义的一个修饰符,可将一个变量声明为一个可空(nullable)值类型。可空值类型在行为上与普通值类型相似,但可以将一个 null 值赋给它。如下所示:

        int? a = null;      // 合法  

    C# 8中基本数据类型除了 string (string是引用类型)外,int、long、float、double、decimal、char、bool (这7中都是值类型)都可以声明为可空值类型。且在方法中使用时,参数位置也没有可空值类型必须在非可空值类型后面的限制,可空值类型可以定义在方法参数 列表的前中后任何位置。

            struct(结构) 类型是值类型,也可以声明为可空值类型。

            对于 string 类型,可以用 string.Empty 输出空值。另外,除了 string.Empty 外,string 类型也可直接赋值为 null。如下:

        string str = null;  // 合法  
        string str = string.Empty;  // 合法  

    代码如下所示:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace 可空类型
    {
        class Program
        {
            static void Main(string[] args)
            {
                Student student1 = new Student();
    
                student1.StudentInformation(12, "boy", 18, 180, 86.0F, 
                    90.0, 95.0M, 85.0F, "Steven", 'A', true, 168);
    
                Console.WriteLine();
    
                student1.StudentInformation(12, "boy", null, null, null, 
                    null, null, 85.0F, "Steven", null, null, 168);
    
                Console.WriteLine();
    
                student1.StudentInformation(12, string.Empty, null, null, null,     
                    null, null, 85.0F, string.Empty, null, null, 168);
    
                    // 对于 string 类型,可以用 string.Empty 输出空值
    
                Console.WriteLine();
    
                student1.StudentInformation(12, null, null, null, null,
                    null, null, 85.0F, null, null, null, 168);
    
                    // 把 赋值给 string 类型的 string.Empty 
                    // 换成 null 后可得到同样的输出
            }
        }
    
        class Student
        {
            //public Student()
            //{
            // 默认构造器注释掉,依然可以运行,实际上程序会自己建一个隐藏的默认构造器
            //}       
            public void StudentInformation(
                int schoolAge,
                string sex,
                int? age,
                long? height,
                float? mathScore,
                double? biologyScore,
                decimal? geographyScore,
                float artScore,
                string name,
                char? scoreGrade,
                bool? passed, 
                int ID)
            {
                Console.WriteLine("Name:            {0}", name);
                Console.WriteLine("ID:              {0}", ID);
                Console.WriteLine("Sex:             {0}", sex);
                Console.WriteLine("Age:             {0}", age);
                Console.WriteLine("SchoolAge:       {0}", schoolAge);
                Console.WriteLine("Height:          {0}", height);
                Console.WriteLine("MathScore:       {0}", mathScore);
                Console.WriteLine("ArtScore:        {0}", artScore);
                Console.WriteLine("BiologyScore:    {0}", biologyScore);
                Console.WriteLine("GeographyScore:  {0}", geographyScore);
                Console.WriteLine("ScoreGrade:      {0}", scoreGrade);
                Console.WriteLine("Passed:          {0}", passed);
            }
        }
    }

      运行后结果如下所示:

    安全地将 bool? 强制转换为 bool(摘自msdn c#编程)

    bool? 可以为 null 的类型可以包含三个不同的值:truefalsenull 因此,bool? 类型不能用于条件语句,如 ifforwhile 例如,以下代码会导致编译器错误。

    bool? b = null;
    if (b) // Error CS0266.
    {
    }

    这是不允许的,因为 null 在条件上下文中的含义并不清楚。 若要在条件语句中使用 bool?,请首先检查其 HasValue 属性以确保其值不是 null,然后将它强制转换为 bool 有关更多信息,请参见 bool 如果对使用 null 值的 bool? 执行强制转换,则在条件测试中将引发 InvalidOperationException 下面的示例演示了一种从 bool? 安全地强制转换为 bool 的方法:

              bool? test = null;
                 ...// Other code that may or may not
                    // give a value to test.
                if(!test.HasValue) //check for a value
                {
                    // Assume that IsInitialized
                    // returns either true or false.
                    test = IsInitialized();
                }
                if((bool)test) //now this cast is safe
                {
                   // Do something.
                }
    string.Empty""

    1、Empty是string类中的一个静态的只读字段,它是这样定义的:

    1. // Summary:  
    2. //     Represents the empty string. This field is read-only.  
    3. public static readonly string Empty;  

           也就是说 string.Empty 的内部实现是等于 "" 的。二者在优化方面稍有差别,string.Empty 是 C# 对 "" 在语法级别的优化。这点可以从上面 string.Empty 的内部实现看出来。也就是说 "" 是通过 CLR(Common Language Runtime)进行优化的,CLR 会维护一个字符串池,以防在堆中创建重复的字符串。而 string.Empty 是一种 C# 语法级别的优化,是在C#编译器将代码编译为 IL (即 MSIL )时进行了优化,即所有对string类的静态字段Empty的访问都会被指向同一引用,以节省内存空间。

            PS:MSILMicrosoft Intermediate Language (MSIL)微软中间语言)。

    2、引用类型的数据将对象在堆上的地址保存在上,将对象的实际数据保存在上。string.Empty与 "" 都会分配存储空间,具体的说是都会在内存的栈和堆上分配存储空间。因此string.Empty与“”都会在栈上保存一个地址,这个地址占4字节,指向内存堆中的某个长度为0的空间,这个空间保存的是string.Empty的实际值。

    由于 string.Empty 定义为 static readonly ,又根据上面运行结果得知, string.Empty 不会申请新的内存,而是每次去指向固定的静态只读内存区域,""也一样。    

            string.Empty 与 "" 在用法与性能上基本没区别。string.Empty 是在语法级别对 "" 的优化。

    二、string.Empty  "" null 的区别

    string.Empty 和 "" 在栈和堆上都分配了空间,而 null 只在栈上分配了空间,在堆上没有分配,也即变量不引用内存中的任何对象。

    ref和out

    ref 实参使用前也必须初始化,否则不能通过编译。使用 ref 关键字,向形参应用的任何操作都同样应用于实参,因为形参和实参引用的是同一个对象。由方法本身来初始化参数,这时可以使用 out 参数。

    as is

    is 和 as 是 C# 提供的以安全的方式执行类型强制转换的操作符,用法如下。

            is 操作符验证对象的类型是不是自己希望的。

        WrappedInt wi = new WrappedInt();  
        object o = wi;  
        if (o is WrappedInt)  
        {  
            WrappedInt temp = (WrappedInt)o;    // 转型是安全的,o 已确定是一个 WrappedInt  
        }  

    as 操作符取一个对象和一个类型作为其左边和右边的操作数。runtime 会尝试将对象转换成指定的类型,若转换成功,就返回转换成功后的结果给 temp,如果转换失败,返回 null 给 temp。

        WrappedInt wi = new WrappedInt();  
        object o = wi;  
        WrappedInt temp = o as WrappedInt;    // 转型是安全的,o 已确定是一个 WrappedInt  
        if (temp != null)  
        {  
            // 只有转换成功,这里的代码才能被执行  
        }  

    http://blog.csdn.net/seattle1215/article/details/6671799  枚举相关

  • 相关阅读:
    vuejs 2 生命周期钩子函数
    js 原型链
    两段代码说明 闭包,变量提升 问题
    node 模块全局位置
    git 提交代码
    mongoose 由一个版本引起的问题
    box-shadow 让div 立体起来
    flexbox 学习笔记 参考阮一峰老师的blog
    Linq的分页与组合查询的配合使用
    发送邮件和数据导出
  • 原文地址:https://www.cnblogs.com/nygfcn1234/p/3368573.html
Copyright © 2020-2023  润新知