美文网首页
设计类型(二)

设计类型(二)

作者: 沈_ac89 | 来源:发表于2019-03-08 00:29 被阅读0次

设计类型

类型和成员基础

基础概念

  1. 友元程序集

    // 在程序集中的AssemblyInfo.cs中,标记友元程序集名称和公钥的字符串参数(如果程序集没有强签名的话,则只要程序集即可)
    [assembly: InternalsVisibleTo("Friend2")]
    [assembly: InternalsVisibleTo("Friend3,PublicKey=xxxxx")]
    // 其中PublicKey来源:
    /*
    1. 创建强类型签名文件test.pfx
    2. 打开cmd窗口,并cd到该目录
    3. 创建强签名文件:sn -k test.snk
    4. 创建私钥: sn -p test.snk test.pk.snk
    5. 提取公钥: sn -pt test.pk.snk
    具体参考蒋金楠老师的博客,或者查看sn的帮助文档
    */
    
  1. 分部类、结构和接口

    主要的作用:

    • 源代码控制,方便协作
    • 同一个文件中将类或结构分解成不同的逻辑单元
    • 代码拆分

    注意:

    • 编译时候会合并,对CLR不可见。
  2. 继承的内存分配(面试基本都会考)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ILLearning
    {
        internal class C
        {
            protected string Hello = "world";
            public virtual void Say(){
                Console.WriteLine("C");
            }
        }
    
        internal class C1 : C
        {
            protected string HelloWorld = "Hello,Kitty";
            protected int i = 4;
            public override void Say()
            {
                var that =  this;
                Console.WriteLine("C1:"+this.i);
                Console.WriteLine("C1:"+that.HelloWorld);
                Console.WriteLine("C1");
            }
        }
    
        internal class C2 : C1
        {
            public override void Say()
            {
             this.Hello = "Kitty";
             this.i = 6;
                this.HelloWorld = "Hello,World";
                Console.WriteLine("C2:"+this.HelloWorld);
                Console.WriteLine("C2:"+this.i);
                /*
                * 主要易错点在这里:
                * 正确的答案是:i=6,HelloWorld="Hello,World",原因是C1的对象没有在这里并没有分配到内存,因此this还是指向C2的对象。
                */
                base.Say();
                Console.WriteLine("C2");
            }
        }
    
        public class CTest
        {
            public static void Main()
            {
                C c = new C2();
                // 分析过程:
                /*
                * new C2()// 开辟C2的堆内存,并向上创建到System.Object,这时候在内存里面已经有Object和C和C1和C2的类型对象
                * 将c指向C2的堆的内存空间,但是只是含有C的公开或者静态的方法或者属性、字段。
                 */
                c.Say();
                // Console.WriteLine(c.Hello); // 不可见
            }
        }
    }
    
  3. 修饰符

    • 注意:protected对于子类都是private(对外来说不可见),但是对于继承链来说,父类都是protected,子类是private。

IL深化(后续补)

  • 调用虚方法等

参考内容

  1. 蒋金楠老师的当InternalsVisibleToAttribute特性遭遇"强签名"

常量和字段

常量

  • const定义的常量总是隐式为static。

字段

重要的字段修饰符

  • Volatile(后续补上)

    
    
  • static和readonly

        public class D
        {
            // 运行时进行初始化,并且不能修改
            public static readonly string a = "test";
            // 可读可写,但是不为对象独有
            private static Int32 b = 0;
            // 在构造函数里面能改变值,不能改变的是引用
            private readonly string c = "test2";
            public D()
            {
                //a = "test1";// 
                this.c = "test3";
            }
    
            public void OutPut() {
                //this.c = "test4";
                b = 5;
            }
        }
    

参考内容

方法

基础概念

  1. 实例构造器与类(引用类型)

    • 实例化过程不调用构造参数的办法

      • Object.MenberwiseClone
      • 反序列化
    • 注意:不要再构造函数中调用虚方法,避免实例字段没有实例化导致的麻烦。

  2. 实例构造器和结构(值类型)

    • C#编译器不允许定义无参构造器
  3. 类型构造器(静态构造器)

    • 线程安全
  4. 操作符重载

    • implicit:告诉编译器为了生成代码来调用方法,不需要在源代码中进行显示转型。
    • explicit:告诉编译器只有在发现了显示转型时,才调用方法。
  // 参考例子
  public class PersonTest : IEquatable<PersonTest>
  {
      public PersonTest()
      {
      }

      public string Id { get; set; }

      public string Name { get; set; }

      public bool Equals(PersonTest other)
      {
          return !object.ReferenceEquals(null, other) && object.ReferenceEquals(this, other);
      }

      public override bool Equals(object obj)
      {
          if (obj == null) return false;
          if (obj.GetType() != this.GetType()) return false;
          return Equals(obj as PersonTest);
      }

      public override int GetHashCode()
      {
          return string.IsNullOrEmpty(this.Id) ? 0 : this.Id.GetHashCode();
      }

      // 默认成对出现,并且一般要覆写Equals和GetHashCode
      public static bool operator ==(PersonTest a, PersonTest b) => !object.ReferenceEquals(null,a) && object.ReferenceEquals(a, b);
      public static bool operator !=(PersonTest a, PersonTest b) => object.ReferenceEquals(null,a) || object.ReferenceEquals(null,b) || !object.ReferenceEquals(a, b);

      /// <summary>
      /// 隐式转换
      /// </summary>
      /// <param name="p"></param>
      public static implicit operator PersonTest(Person p){
          return new PersonTest { Id = p.Id };
      }

      /// <summary>
      /// 显示转换成其他对象
      /// </summary>
      /// <param name="p"></param>
      public static explicit operator Person(PersonTest p)
      {
          return new Person { Id = p.Id };
      }

  }

  public class Person
  {
      public string Id { get; set; }
  }
  1. 扩展方法

  2. 分部方法

        partial class E
        {
            private string _name;
            partial void OnNameChange(string value);
    
    
            public string Name
            {
                get { return _name; }
                set
                {
                    OnNameChange(value.ToUpper());
                    _name = value;
                }
            }
        }
    
        ///// <summary>
        ///// 如果没有实现分部方法,IL里面不会进行调用
        ///// </summary>
        //partial class E {
        //    partial void OnNameChange(string value)
        //    {
        //        Console.WriteLine("");
        //    }
        //}
    
        class E1 : E
        {
            
        }
    
    • 规则和原则
      • 只能在分部类或结构中声明
      • 分部方法的返回类型始终是void,任何参数都不能用out修饰符来标记。
      • 分部方法的声明和实现必须具有完全一致的签名,定制特性会例外,??
      • 如果没有对应的实现部分,不能再代码中创建一个委托来引用这个分部方法。
      • 分部方法总是被视为private方法。

参数

基础概念

  1. 规则和原则

    • 可为方法、构造器方法和有参属性(C#索引器)的参数指定默认值。
    • 可为委托定义一部分的参数指定默认值。
    • 有默认值的参数必须放在没有默认值的所有参数之后。
    • 默认值必须是编译时能确定的常量值。
    • 不要重命名参数变量,调用方可能会使用命名参数,可能会提示CS1739的错误。
    • 如果方法从模块外部掉哟那个,更改参数的默认值具有潜在的危险性。
    • 如果参数用ref或out关键字进行标识,就不能设置默认值。
    • 可选或命名参数调用方法,附加规则:
      • 实参可以按人仪顺序传递,但命名实参智能出现在实参的尾部。
      • 可按名称将实参传给没有默认值的参数。
      • C#不允许省略逗号之间的实参。
      • 如果参数要求ref/out,为了以传参数名的方式传递实参。
  2. 隐士类型的局部变量

  3. ref和out关键字

  4. 向方法传递可变数量的参数(params)

  5. 参数和返回类型的设计规范

    • 说明方法的参数类型时,应尽量指定最弱的类型。
    • 相反,一般最好是将方法的返回类型声明为最强的类型。

属性

基础概念

  1. System.Tuple
  2. 有参属性

相关文章

  • 设计类型(二)

    设计类型 类型和成员基础 基础概念 友元程序集// 在程序集中的AssemblyInfo.cs中,标记友元程序集名...

  • Kotlin基础认识 (5)可空数据类型

    一、可空类型概念 Kotlin的非空类型设计能够有效防止空指针异常。 定义可空类型 二、使用安全调用运算符 (?....

  • 教学设计

    《世界气候类型的分布》教学设计 一、内容标准 运用世界气候类型分布图说出主要气候类型的分布。 二、学习目标 1.运...

  • 消息的类型设计MsgBox(二)

    1、MsgBox(msg, vbYesNo)的应用,当你激活了一个弹出对话框时,指明了一个操作事项,要求你看到了提...

  • 设计类型

    设计类型 一、类型基础 常见问题 面向对象语言的特点? 什么是面向对象语言面向对象语言(Object-Orient...

  • kotlin基础篇(1)--"null"

    欢迎关注 二师兄Kotlin转载请注明出处 二师兄kotlin kotlin "null" Kotlin的类型设计...

  • 设计模式的原则及UML类图

    设计模式类型 设计模式分为三种类型: 创建型模式 结构型模式 行为型模式 设计原则 软件开发的23种设计模式,就是...

  • MySQL 业务设计(设计表中内容)

    逻辑设计 第一范式: 所有字段都是单一属性 单一属性是由基本数据类型所构成的 设计出来的表都是简单的二维表 第二范...

  • Modern Fortran Explained学习笔记3

    继续第二章的内容 今天学习了一个挺重要的内容派生数据类型 派生数据类型 这种数据类型其实是一种面向对象的设计方法,...

  • 设计模式类型

    1创建模式 这些模式提供了一种创建对象的同时隐藏创建逻辑的方式,而不是使用new运算符直接实例化对象。这使得程序在...

网友评论

      本文标题:设计类型(二)

      本文链接:https://www.haomeiwen.com/subject/sekfpqtx.html