zoukankan      html  css  js  c++  java
  • C#无参属性

    大家来讨论下C#无参属性这个东西到底有没有存在的必要?

    永远不要公开类型的字段,面向对象设计和编程的重要原则之一就是 数据封装。如果公开类型的字段,会很容易的写出不恰当使用字段的代码。这里可以把字段声明为private,然后声明访问器方法。

        class test
    {

    private string Name;
    public void SetName(string value)
    {
    Name = value;
    }
    public string GetName()
    {
    return Name;
    }

    }

    实现只读或只写就是这么简单,不实现一个索引器方法就行了。还可以将Setname方法标记为protected,就可以只允许派生类修改了。聪明的你也发现上面这个做法的缺点了吧,首先得去实现额外的方法,所以会产生更多的代码,其次,如果调用的时候必须调用方法,不能直接引用一个字段名。还好C#给我们提供了一个称为属性(property)的机制,它缓解了第一个缺点造成的影响,也消除了第二个缺点。

       class test
    {

    private string name;
    public string Name {
    get { return name; }
    set { if ("狗剩" == value) { Console.WriteLine("系统崩溃,抛出异常"); return; } name = value; }
    }

    }

    属性可以用任意的可访问修饰符来标记。不能定义名称相同的属性。

    如果只是为了封装一个支持字段而创建属性,C#还提供一一种更简单的语法,称为自动实现的属性(Automatically Implemented Property,简称AIP)。like this

       class test
    {
    public int Age
    {
    get;
    set;
    }
    }

    如果声明一个属性而不提供get/set实现,C#会自动为你声明一个私有字段。原始代码是这样的:

    public int Age
    {
    [CompilerGenerated]
    get
    {
    int num;
    num = this.<Age>k__BackingField;
    Label_0009:
    return num;
    }
    [CompilerGenerated]
    set
    {
    this.<Age>k__BackingField = value;
    return;
    }
    }

    和直接声明一个public 的Age字段相比,自动实现的属性的优势在哪?两者存在一处重要的区别:使用自动实现的属性(AIP)意味着已经创建一个属性,访问该属性的时候会调用get/set方法。如果有一天你决定自己实现这个AIP的get/set,而不接受编译器默认的实现,那么访问这个属性的任何代码都不必重新编译。如果是一个public的Age字段,如果你把它更改为属性,那么访问这个字段的所有代码就都需要重新编译了。

    凡事都有好有坏,那么AIP有哪些不讨人喜欢的地方呢

    1.如果使用字段声明的语法,可以包含初始化的部分,如果使用AIP就不行了,必须在咩个构造器中显示的初始化每个AIP。

    2.AIP支持的字段名是由编译器决定的,而且每次重新编译,这个字段名可能会发生更改,这样一来,只要含有一个AIP就不能对类型的实例进行反序列化了。在任何想要序列化或反序列化的类型中,都不要使用AIP功能。

    3.不能在AIP的get/set添加断点,所以不好检测程序在什么时候获取或设置这个属性。咱手动实现的就可以设置断点,不信你试试。

    AIP功能是作用于整个属性的:要么都用,要么都不用,这意味这,如果显式的实现get那么set也要显式实现,反之亦然。

    属性看起来与字段相似,但本质上是方法。属性与字段的区别如下:

    1.属性可以是只读或只写的(get/set访问器方法),字段却总是可读可写的。

    2.属性方法可能抛出异常,字段访问不会抛出。

    3.属性不能作为out或ref参数传递给方法,字段可以。

    class Program
    {
    public int Age
    {
    get {return 3 ;}
    set{}
    }
    int age;
    static void Main()
    {
    var t = new { name="XiaoBai",age=22 };
    test tt = new test();
    //tt.Name = "狗剩";
    Program p = new Program();
    some(out p.age);
    some(out p.Age);//属性,索引器或动态成员不得作为out或ref参数传递
    Console.ReadKey();
    }
    static void some(out int age)
    {
    age = 10;
    }
    }

    4.属性方法可能花费较长时间执行,字段的访问都是立即完成。

    5.属性方法可能需要额外的内存,或者返回一个不正确的引用,指向不属于对象状态一部分的某个东西,这样一来,对返回对象的修改就作用不到原始对象身上了,相反查询字段返回的总是正确的引用,它指向的东西保证是原始对象状态的一部分。使用会返回一个拷贝的属性时,非常容易引起混淆。

    如果仔细研究下属性和字段的差别,你会发现只有在极个别的情况下属性才真正有用。属性唯一的好处就是提供了简化的语法,和调用普通方法(非属性中的方法)相比,属性不仅不会提升代码的性能,还会妨碍对代码的理解。

    属性访问器的可访问性:

    我们有时希望为get访问器指定一种可访问性,为set访问器指定另一种访问器:

        class test
    {
    public int Age
    {
    get { return age; }
    protected set { if (value < 0) Console.WriteLine("年龄错误!"); else { age = value; } }
    }
    int age;
    }

    如上所述,Age属性本身声明为public,意味这get访问器方法是公共的,可由所有代码访问,但是,注意set访问器方法被声明为protected,只能从test的内部定义的代码中调用,或者从test的派生类的代码中调用。

    定义一个属性时,如果两个访问其方法需要具有不同的可访问性,C#语法要求必须为属性本身指定限制最不大的那一种可访问性,然后在两个访问其中,只能选择一个来应用限制较大的那一种可访问性。在前面的例子中,属性本身为public,set访问器为protected(限制比public大)。

       class test
    {
    private int Age
    {
    get { return age; }
    protected set { if (value < 0) Console.WriteLine("年龄错误!"); else { age = value; } }//这里就通不过编译
    }
    int age;
    }




  • 相关阅读:
    【DDD】领域驱动设计实践 —— 架构风格及架构实例
    【DDD】领域驱动设计精要
    Zynq UltraScale+ cross compiler
    Platform device/driver注册过程 (转)
    static inline extern等概念
    (int argc, char *argv[]) 指针数组
    linux man 1,2,3 命令
    指针左值错误
    arm ds5 编译选项
    在JTAG菊花链拓扑对设备编程
  • 原文地址:https://www.cnblogs.com/smailxiaobai/p/2280393.html
Copyright © 2011-2022 走看看