.net深入体验与实战精要--细节决定成败

1.Equals()和运算符==的区别

因为值类型是存储在内存中的堆栈(下面简称栈),而引用类型的变量在栈中仅仅存储引用类型的地址,其本身则存储在堆中。

//对值类型 
        static void Main(string[] args)
        {
            int n1 = 1;
            int n2 = 1;
            Console.WriteLine(n1 == n2);//true
            Console.WriteLine(n1.Equals(n2));//true
            //

            string s1 = "test";
            string s2 = "test";
            Console.WriteLine(s1 == s2);//ture
            Console.WriteLine(s1.Equals(s2));//我认为false,但是结果是true

            string s3 = s1;
            Console.WriteLine(s3 == s1);//true
            Console.WriteLine(s3.Equals(s1));//true
            Console.WriteLine(s3 == s2);//true
            Console.WriteLine(s3.Equals(s2));//我认为false,但是结果是true

            Console.ReadKey();
        }
 public class ClassPerson
    {
        public ClassPerson(string strname)
        {
            name = strname;
        }
        private string name = null;
        public string Name
        {
            set { name = value; }
            get { return name; }
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            string s1 = "test";
            string s2 = "test";
            Console.WriteLine(s1 == s2); //True
            Console.WriteLine(s1.Equals(s2)); //True

            object o1 = s1;
            object o2 = s2;
            Console.WriteLine(o1 == o2); //True
            Console.WriteLine(o1.Equals(o2)); //True

            string s3 = new string(new char[] { t, e, s, t });
            string s4 = new string(new char[] { t, e, s, t });
            Console.WriteLine(s3 == s4);  //True
            Console.WriteLine(s3.Equals(s4));  //True

            object o3 = s3;
            object o4 = s4;
            Console.WriteLine(o3 == o4); //False
            Console.WriteLine(o3.Equals(o4)); //True

            ClassPerson p1 = new ClassPerson("ltp");
            ClassPerson p2 = new ClassPerson("ltp");
            Console.WriteLine(p1 == p2);  //False
            Console.WriteLine(p1.Equals(p2)); //False

            ClassPerson p3 = new ClassPerson("ltp");
            ClassPerson p4 = p3;
            Console.WriteLine(p3 == p4); //True
            Console.WriteLine(p3.Equals(p4)); //True

            Console.ReadKey();

        }
    }

2.const和readonly的区别

  • readonly和const都是用来表示常量的
  • 初始化赋值不同
//const修饰的常量必须在声明的同时赋值 
public class Class1
{
    public const int va=10;//正确
    public const int vb;// 错误
    public Class1()
    {
        vb=10;
    }
}
 
//readonly 字段可以在初始化(声明或构造函数)的过程中赋值,在其他地方不能赋值
public class Class1
{
    public readonly int i=10;//right
    public readonly int z;
    public Class1()
    {
        z=1;//right;
    }
    protected void Load()
    {
        z=1;//wrong 无法对制度的字段赋值(构造函数或变量出事值制定项中除外)
    }
}
  • const是编译时的常数,readonly字段可荣誉运行时常数
//right
public const int n=1;
public const int m=n+1;
//wrong
public const int a;
public const int b=a+1;
  • readonly是计算时执行的。
public static readonly uint nowtime=(uint)DateTime.Now.Ticks;
public static readonly string ConnectionString=Configuration.AppSettings["SQLConnectring"];
  • const默认就是静态的,而readonly如果设置成静态的就必须显示声明
  • object,Array(数组)和struct(结构)不能被声明为const常量
  • const和static readonly

sealed,new,virtual,abstract与override

  • sealed——断子绝孙
  • new——你是你的,我是我的
  • virtual——为了子孙后代
  • abstract——我是上帝
  • override——一手遮天
    public class BaseClass
    {
        public BaseClass()
        {
            Console.WriteLine(" 基类构造");
        }
        public virtual void Method() //使用virtual才可以在子类中使用override,而new不必要
        {
            Console.WriteLine(" 基类.Method()");
        }
    }
    public class DeriveClassA : BaseClass
    {
        public DeriveClassA()
        {
            Console.WriteLine(" 类A.构造");
        }
        public override void Method()
        {
            //base.Method();
            Console.WriteLine(" 类A.Method() in override");
        }
    }
    public class DeriveClassB : BaseClass
    {
        public DeriveClassB()
        {
            Console.WriteLine(" 类B.构造");
        }
        public new void Method()
        {
            //base.Method();
            Console.WriteLine(" 类B.Method() in new");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            BaseClass ba1 = (BaseClass)new DeriveClassA();//类型转换
            ba1.Method(); //用override重写方法,是基类的一个派生,所以这里通过基类的虚函数,会访问到派生类的方法。
            Console.WriteLine(" =================");

            BaseClass bb2 = (BaseClass)new DeriveClassB();
            bb2.Method(); //用new重写方法,是一个和基类无关的新方法,所以这里基类调用的时候,访问基类的方法。
            Console.WriteLine(" =================");

            DeriveClassA a1 = new DeriveClassA();
            a1.Method();
            Console.WriteLine(" =================");

            DeriveClassB b2 = new DeriveClassB();
            b2.Method();
            Console.WriteLine(" =================");
            Console.ReadKey();

        }
    }

 

公共变量与属性的区别

成员变量

public string Name

类属性

public class People
{
    private string name;
    public string Name
    {
        set
        {
            name=value;
        }
        get
        {
            return name;
        }
    }    
}

 

总结:

  • 属性是对字段的封装
  • 属性可以控制读写,变量不可以
  • 属性可以进行操作,变量不可以

参数修饰符params,out和ref的区别

params——一个可以唱方法拥有的可变参数的关键字

 public class Program
    {
        static void UseParams(params int[] list)
        {
            string temp = "";
            for (int i = 0; i < list.Length; i++)
            {
                temp = temp + " " + list[i].ToString();
            }
            Console.WriteLine(temp);
        }
        static void UseParams2(params object[] list)
        {
            string temp = "";
            for (int i = 0; i < list.Length; i++)
            {
                temp = temp + " " + list[i].ToString();
            }
            Console.WriteLine(temp);
        }
        static void Main()
        {
            UseParams(1, 2, 3);//看参数是3个
            UseParams(1, 2);   //看参数是2个,可变吧

            UseParams2(1, a, "test");

            int[] myarray = new int[3] { 10, 11, 12 };
            UseParams(myarray); //看也可以是容器类,可变吧:)
            Console.ReadKey();
        }
    }

 

out——一个引用参数

当一个方法在使用out作为参数时,在方法中对out参数所做的任何改变都将方应在变量中

static void Main()
{
    int value;//不必初始化
    Method(out value);//显示使用out关键字
    Console.WriteLine(value);//value is now 44
}
static void Method(out int i)
{
    i=44
}

 

当希望方法返回多个值时,声明out方法非常有用。

static void Main()
{
    int value;
    string str1,str2;
    Method(out value,out str1,out str2);
    Console.WriteLine(value);
    Console.WriteLine(str2);
    Console.WriteLine(str3);
}
static void Method(out int i , out string s1,out string s2)
{
    int 1=44;
    s1="返回第二个参数";
    s2=null;
}

 

若要使用out参数,则方法定义和调用方法都要显式使用out关键字。

不必初始化作为out参数传递的变量,ref要求变量必须在传递之前进行初始化

属性不是变量不能作为out参数传递

如果两个方法的声明仅在out的使用方面不同,则会发生重载,不过无法定义仅在ref和out方面的不同重载,例如如下是有效的

class MyClass
{
    public void MyMethod(int i)
    {
        i=10;
    }
    public void MyMethod(out int i)
    {
        i=10;
    }
}

 

而下面是无效的

class MyClass
{
    public void MyMethod(out int i)
    {
        i=10;
    }
    public void MyMethod(ref int i)
    {
        i=10;
    }
}

 

ref——仅仅是一个地址

当一个方法在使用ref作为参数时,在方法中对ref参数所做任何改变都反映在改变量中

static void Main()
{
    int value=0;          //必须初始化
    Method(ref value);    //显式使用ref关键字
    Console.Write(value); //value is now 44
}
static void Method(ref int i)
{
    i=44;
}

 

同样的下面的是有效的

class MyClass
{
    public void MyMethod(int i)
    {
        i=10;
    }
    public void MyMethod(ref int i)
    {
        i=10;
    }
}

 

而下面的是无效的

class MyClass
{
    public void MyMethod(out int i)
    {
        i=10;
    }
    public void MyMethod(ref int i)
    {
        i=10;
    }
}

 

ref和out示例

public static string TestOut(out string i)
{
    i="out b";
    return "return value";
}
public static void TestRef(ref string i )
{
    //改变参数
    i="ref b"
}
public static void TestNoRef(string refi)
{
    //不用改变任何东西
    refi="on c";
}
static void Main()
{
    string outi ;//不需要初始化
    Console.Write(TestOut(out outi));//返回值 输入“return value”
    Console.Write(outi);

    string refi ="a";//必须初始化
    TestRef(ref refi);
    Console.WriteLine(refi);//输出ref b

    TestNoRef(refi);//不适用ref
    Console.WriteLine(refi) //仍然输出ref b  没变
}

 

值类型和引用类型的区别

类和结构的区别

一个是引用类型,一个是值类型

继承性——struct没有继承性,但是结构可以实现接口

interface IPerson
{
    void eat();
}
struct Man:IPerson
{
    public void eat()
    {
        //实现接口
    }
    private int x,y,z;//其他结构成员
}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。