首页 > 编程语言 >《NET CLR via C#》---第十章(无参属性,对象和集合初始化器,匿名类型,元组,有参属性)

《NET CLR via C#》---第十章(无参属性,对象和集合初始化器,匿名类型,元组,有参属性)

时间:2024-09-02 17:16:36浏览次数:5  
标签:无参 via name age 类型 new public 属性

面向对象设计和编程的重要原则之一就是数据封装,意味着类型的字段永远不应该公开,否则很容易因为不恰当使用字段而破坏对象的状态。


无参属性

对于类型中数据字段的封装,有以下3点好处:

  1. 可能希望访问字段来执行一些“副作用”,缓存某些值或者推迟创建一些内部对象
  2. 可能希望以线程安全的方式访问字段
  3. 字段可能是一个逻辑字段,它的值不由内存中的字节表示,而是通过某个算法来计算获得
public sealed class Employee
{
    private int m_age1;

    public int get_Age()
    {
        return m_age1;
    }

    public void set_Age(int value)
    {
        m_age1 = value;
    }

    // 等效于;编译器在指定的属性名之前自动附加get或者set前缀
    private int m_age2;
    public int M_age2 { get => m_age2; set => m_age2 = value; }

    // 等效于;C#提供更简洁的语法,称为自动实现的属性(Automatically Implemented Property,AIP)
    public int M_age3 { get; set; }
}

使用AIP,意味着你已经创建了一个属性。访问该属性的任何代码实际都会调用get和set方法。如果以后你决定自己实现get或set方法,而不是接受编译器的默认实现,访问属性的任何代码都不必重新编译。

但AIP有个问题是,运行时序列化引擎将字段名持久存储在序列化的流中。AIP的支持字段名称由编译器决定,每次重新编译代码都可能更改这个名称。因此,任何类型只要含有一个AIP,就没办法对该类型的实例进行反实例化。在任何想要序列化或反序列化的类型中,都不要使用AIP功能。

除此之外,如果使用AIP,属性必然是可读和可写的。

对象和集合初始化器

经常要构建一个对象并设置对象的一些公共属性(或字段)。为了简化这个常见的编程模式,C#语言支持了一种特殊的对象初始化语法。

public sealed class Employee
{
    public string name;
    public int age;
}

public class Program
{
    static void Main(string[] args)
    {
        Employee e1 = new Employee() { name = "Jeff", age = 45 };

        // 等效于
        Employee e2 = new Employee();
        e2.name = "Jeff";
        e2.age = 45;
    }
}

如果属性的类型实现了IEnumerable或IEnumerable<T>接口,属性就被认为是集合,而集合的初始化是一种相加(additive)操作,而非替换(replacement)操作。例如:

public sealed class ClassRoom
{
    public List<string> students = new List<string>();
}

public class Program
{
    static void Main(string[] args)
    {
        ClassRoom c1 = new ClassRoom() { students = new List<string>() { "A", "B", "C" } };

        // 等效于
        ClassRoom c2 = new ClassRoom();
        c2.students.Add("A");
        c2.students.Add("B");
        c2.students.Add("C");
    }
}

匿名类型

我们可以在不定义类型的情况,去创建一个自定义的类型实例,例如:

public class Program
{
    static void Main(string[] args)
    {
        // 定义类型,构造实例,并初始化属性
        var o1 = new { name = "Jeff", age = 45 };
        Console.WriteLine($"name:{o1.name},age:{o1.age}");
    }
}

第一行代码创建了匿名类型,没有在new关键字后指定类型名称,所以编译器会自动创建类型名称,而且我们无法知道这个名称是什么(正是匿名的含义)。

编译器会推断每个表达式的类型,创建推断类型的私有字段,为每个字段创建公共只读属性,并创建一个构造器来接受所有这些表达式。除此之外,编译器还会重写Object的Equals,GetHashCode和ToString方法,并生成所有这些方法的代码,类似这种:

internal sealed class f_AnonymousType0: Object
{
    private readonly string name;
    private readonly int age;

    public string Name => name;
    public int Age => age;

    public f_AnonymousType0(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public override bool Equals(object obj)
    {
        ....
    }

    public override int GetHashCode()
    {
        ....
    }

    public override string ToString()
    {
        ...
    }
}

编译器会生成Equals和GetHashCode方法,因此匿名方法的实例能放到哈希表集合中。属性是只读的,而非可读可写,目的是防止对象的哈希码发送改变。

编译器在定义匿名类型时是非常“善解人意”的。如果它看到你在源代码中定义了多个匿名类型,而且这些类型具有相同的结构,那么它只会创建一个匿名类型定义,但创建该类型的多个实例。

由于类型相等,所以我们可以检查2个对象是否包含相等的值,并将一个对象的引用赋给另一个对象的变量,比如:

public class Program
{
    static void Main(string[] args)
    {
        var o1 = new { name = "Jeff", age = 45 };
        var o2 = new { name = "Petter", age = 25 };

        Console.WriteLine($"isEqual:{o1.Equals(o2)}");
        o2 = o1;
    }
}

也可以创建一个隐式类型的数据,在其中包含一组匿名类型的对象,比如:

public class Program
{
    static void Main(string[] args)
    {
        var perpon = new[]
        {
            new {name = "Jeff", age = 45},
            new {name = "Petter", age = 25}
        };
    }
}

元组

匿名类型的实例不能泄露到方法外部。方法原型不能接受匿名类型的参数,因为无法指定匿名类型。这个时候,就可以利用到元组了。在System命名空间,Microsoft定义了几个泛型Tuple类型,它们全部从Object派生,区别只在于元数(泛型参数的个数)。最简单的元组如下:

public class Tuple<T1>
{
    private T1 m_Item1;
    public Tuple(T1 item1) { m_Item1 = item1; }
    public T1 Item1 => m_Item1;
}

有参属性

无参属性get,set访问权不接受参数,有参属性则反过来,它的get或set访问器可以接受多个参数,有参属性亦称索引器。C#使用数组风格的语法来公开有参属性(索引器)。下面是一个示例:

public class WeekDays
{
    private string[] days = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };

    public string this[int index]
    {
        get
        {
            if (index < 0 || index >= days.Length)
            {
                throw new IndexOutOfRangeException("Index out of range.");
            }
            return days[index];
        }
        set
        {
            if (index < 0 || index >= days.Length)
            {
                throw new IndexOutOfRangeException("Index out of range.");
            }
            days[index] = value;
        }
    }
}

所有索引器至少要有一个参数,或者更多。这些参数(和返回类型)可以是除了void之外的任意类型。C#允许一个类型定义多个所引起,只要索引器的参数集不同

调用属性访问器时的性能

对于简单的get和set访问器方法,JIT编译器会将代码内联。这样一来,使用属性就没有性能上的损失。内联是指将方法的代码直接编译到调用它的方法中。这就避免了在运行时发出调用所产生的开销,代价是编译好的方法变得更大。由于属性访问器方法包含的代码一般很少,所以对内联会使生成的本机代码变得更小,而且执行更快。

标签:无参,via,name,age,类型,new,public,属性
From: https://www.cnblogs.com/chenxiayun/p/18390397

相关文章

  • 【好用小方法】随机生成n个汉字/数字转汉字/字符串去重/list数组去重/获取2的幂次方/
    /***根据参数生成n个中文汉字**@paramnum*@return*/publicstaticList<String>getChaineseList(intnum,List<String>aa){if(num<=0)returnaa;Stringword="";if(aa.size()>0){for(Strings:aa)......
  • PrimeVue DataTable 属性值解析
    primeVueDataTable组件的属性值使用DataTable属性NameTypeDefaultdescriptionvaluenull|any[]null要显示的对象数组。dataKeystring|Functionnull唯一标识数据中的记录的字段名称。rowsnumber0每页显示的行数。firstnumber0要显示的第一行的索引。totalR......
  • Java数据库事务管理:ACID属性的实现与应用
    Java数据库事务管理:ACID属性的实现与应用大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代软件开发中,数据库事务管理是确保数据一致性和完整性的关键。ACID属性是事务处理的基石,包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久......
  • Java反射机制:动态访问和修改类属性
    Java反射机制:动态访问和修改类属性大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!Java的反射机制是一种强大的工具,它允许程序在运行时访问和修改类的属性和方法。通过反射,我们可以在不直接引用类的情况下,动态地创建对象、调用方法、修改字段等。本文......
  • HTML表单中input标签中的type属性使用
     type属性表示表单控件的类型一,radio,checkbox,date,time,datetime-local,month,week等    1.radio:单选框             单选中一组内容必须设置同一个name名;                单选中每一个表单控件必须设置value......
  • spring 自定义属性解析器
    自定义属性解析器org.springframework.context.support.AbstractApplicationContext#prepareBeanFactorybeanFactory.setBeanClassLoader(getClassLoader());//设置EL表达式解析器(${})beanFactory.setBeanExpressionResolver(newStandardBeanExpressionResolver(beanFactory.g......
  • computed计算属性及方法对比和循环遍历统计以及watch和watchEect监听的用法
    1.computed计算属性及方法对比1.了解computed计算属性和用法在我们的一些应用中可以看的应用会给我们提供一些计算类的功能比如取名,它会给你提供两个输入框,然后在你给这两个输入框输入值的时候会在下方生成你输入这个两个值的结合值,就比如你先输入了一个姓氏,然后输入一个名,下......
  • PoLLMgraph: Unraveling Hallucinations in Large Language Models via State Transit
    本文是LLM系列文章,针对《PoLLMgraph:UnravelingHallucinationsinLargeLanguageModelsviaStateTransitionDynamics》的翻译。PoLLMgraph:通过状态转换动力学揭示大型语言模型中的幻觉摘要1引言2相关工作3PoLLMgraph4实验5结论局限性摘要尽管近......
  • 前端css网格布局----行列属性
     固定值方式尽量撑满宽和高三行三列grid-template-rows:200px200px200px;grid-template-columns:200px200px200px;百分比方式四行四列 grid-template-rows:25%25%25%25%;grid-template-columns:25%25%25%25%;repeat(重复几次,数值) 3行3列  g......
  • Java替换RequstBody和RequestParam参数的属性
    Java替换RequstBody和RequestParam参数的属性本文主要讲解在Java环境中如何替换RequestBody和RequestParam参数中的属性背景近期由于接手的老项目中存在所有接口中新增一个加密串来给接口做一个加密效果(项目历史原因,不方便上Jwt授权这套),所以就研究了一下Http请求链路,发现可以......