代码改变世界

C# Tips

2009-05-07 12:30  宗哥  阅读(1659)  评论(10编辑  收藏  举报

1.值类型和引用类型

    对于C#的变量来说,有两种类型,值类型(Value Type)和引用类型(Reverence Type)。两者不同点:
  • 值类型继承自ValueType
    如下图:

        clip_image002[13]

  • 两者存储方式不同:
    值类型变量存储在栈当中。引用类型内存数据结构表示分有两部分构成,一部分引用,存储在在栈中, 一部为实际变量成员,存储在在堆中。
    如图:
    clip_image002[17]
    注意:以上情况是指值类型和引用类型不是作为引用类型的成员,如果作为引用类型变量成员,值类型的数据和引用类型的引用都存储在栈中。

2.方法的参数修饰符 ref ,out ,params:

  • 默认情况下,对于值类型参数的传递,其形参(Formal parameter)是实参(Formal parameter)的拷贝。在方法中对于形参所作的任何更改不会影响到实参。 对于引用类型的参数的传递,其形参(Formal parameter)是实参(Formal parameter)的部分拷贝(shallow clone),通常也叫浅拷贝。 形参只拷贝了的引用部分(即:在栈中存储的部分),这个引用同样指向实参的在堆(Heap)中的对象数据。 在这种情况下,方法内部对于形参的引用指向的成员数据改变将反映到实参,而对于形参的引用本身的更改不会影响到实参。
    例:
    class MyClass

        
    public int Val = 20;
    }

    class Program
    {
        
    static void MyMethod(MyClass f1, int f2)
        {
            f1.Val 
    = f1.Val + 5;
            f2 
    = f2 + 5;
            f1 
    = new MyClass();
        }
        
    static void Main()
        {
            MyClass A1 
    = new MyClass();
            
    int A2 = 10;
            MyMethod(A1, A2); 
    // Call the method.
        }
    }

    clip_image002[19]
  • 对于Ref参数修饰符号,对于值类型参数的传递,其形参(Formal parameter)和实参(Formal parameter)是栈中同一个数据块。在方法中对于形参所作的更改在控制回调时会反映到实参。对于引用类型的参数的传递,其形参(Formal parameter)是实参(Formal parameter)是指同一个变量(栈中Reverence引用部分和堆中object数据部分),在方法中对于形参所作的更改在控制回调时当然会反映到实参 。例:
    class MyClass
    public int Val = 20; } // Initialize field to 20.
    class Program
    {
        
    static void MyMethod(ref MyClass f1, ref int f2)
        {
            f1.Val 
    = f1.Val + 5// Add 5 to field of f1 param.
            f2 = f2 + 5// Add 5 to second param.
            f1 = new MyClass();
        }
        
    static void Main()
        {
            MyClass A1 
    = new MyClass();
            
    int A2 = 10;
            MyMethod(
    ref A1, ref A2); // Call the method.
        }
    }

     
    clip_image002[21]
    Out参数修饰符Ref功能类似,如果两个方法签名仅仅在ref或者out方面使用不同,都会引起重载(overload),
    例如:
    class MyClass
    {
        
    public void MyMethod(int i){ i = 10;}

        
    public void MyMethod(ref int i){ i = 10;}
    }
    但是在OUT和ref之间无法定义重栽。如以下例子是无效的重载(但是编译可以通过):
    class MyClass
    {
        
    public void MyMethod(out int i){ i = 10;}

        
    public void MyMethod(ref int i){ i = 10;}
    }
    区别如下:
    Out在控制回调前,必须在方法体内进行形参赋值。
    Ref在方法调用前,必须对实参进行显式的赋值。
  • params 关键字指定在参数数目可变,具体经典用法例子在微软PetShop的数据访问层的SQLHelper中可见。

3.类,对象,引用

  • 类(class)是在内存中看得到摸得着的类型实例的一个蓝图,是对象的特性的抽象和行为的概括。通常,类在扩展文件名为.CS的代码文件中被定义。
  • 通常一旦类被定义,你可以用使用New关键字生成任何对象(object),对象是类的一个实例(instance)。
  • 但是,new关键字返回堆(heap)的引用(references),并不是这个实际的对象(object)本身,而你在应用程序当中使用的这个引用(references)变量是存在于栈(Stack),如果调用用这个对象的(Object)的属性和方法,使用.(Dot)操作符号。对于引用(references)的定义和解释,你可以借助图来理解。
;