读改善c#代码157个建议:建议13~15

目录:

  • 建议13:为类型输出格式化字符串
  • 建议14:正确实现浅拷贝和深拷贝
  • 建议15:使用dynamic来简化反射实现

一、建议13:为类型输出格式化字符串

有些类型需要我们根据业务需求提供字符串的格式化输出。

1、我们明确知道业务需求什么样的输出格式,也就是类型主动格式化输出。

可以重写Object.ToString()方法,也可以继承IFormattable接口实现ToString,对字符串进行输出。

class Person :IFormattable
    {
        public string IDCode { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            switch (format)
            {
                case "CH": return this.ToString();
                case "US": return string.Format("{0}{1}", LastName, FirstName);
                default: return this.ToString();
            }
        }

        public override string ToString()
        {
            return string.Format("{0}{1}", FirstName,LastName);
        }
    }

客户端:

 Person p = new Person() { IDCode = "No1", FirstName = "Sun", LastName = "N" };

            Console.WriteLine(p);

            Console.WriteLine(p.ToString("CH", null));
            Console.WriteLine(p.ToString("US", null));

            Console.ReadKey();

实例:记得之前做过一个API展示:API的Name是英文名,还有一个字段描述。现在我想看到API.ToString()展示的格式是:英文名:描述。就可以稍微重写ToString()进行格式化输出。

         public override string ToString()
        {
            if (!string.IsNullOrEmpty(this.ApiName) && !string.IsNullOrEmpty(this.Description))
                return string.Format("{0}:{1}", this.ApiName, this.Description);

            return string.Empty;
        }

2、使用格式化器进行格式化输出

如果类不能提供字符串的格式化输出,我们就可以使用格式化器,好处是我们可以根据需求修改格式化器的输出。

 class Person
    {
        public string IDCode { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

格式化器:典型的格式化器应该继承IFormatProvider(继承这个接口有什么作用?), ICustomFormatter

class PersonFormatter : IFormatProvider, ICustomFormatter
    {
        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter))
                return this;
            else
                return null;
        }

        public string Format(string format, object arg, IFormatProvider formatProvider=null)
        {
            Person p = arg as Person;
            if (p == null)
                return string.Empty;

            switch (format)
            {
                case "CH": return string.Format("{0}{1}", p.FirstName, p.LastName);
                case "US": return string.Format("{0}{1}", p.LastName, p.FirstName);
                default: return string.Format("{0}{1}", p.FirstName, p.LastName);
            }
        }
    }

客户端:

 Person p = new Person() { IDCode = "No1", FirstName = "Sun", LastName = "N" };

            //不重写ToString,返回类型名称
            Console.WriteLine(p.ToString());

            PersonFormatter pf = new PersonFormatter();

            Console.WriteLine(pf.Format("CH", p));

            Console.WriteLine(pf.Format("US", p));

            Console.WriteLine(pf.Format("", p));

            Console.ReadKey();

运行:

二、建议14:正确实现浅拷贝和深拷贝

建议继承ICloneable接口。浅拷贝,拷贝的对象中的引用类型的值的改变会互相影响。而深拷贝就是为了解决浅拷贝的这个问题。

下面是继承了ICloneable接口,并实现了浅拷贝和深拷贝的类。

这里的深拷贝的实现方法是使用序列化格式化器:BinaryFormatter,将类成员信息序列化成二进制流,然后反序列化成当前类。这里使用序列化所以类需要加上特性[Serializable],以示此类具有序列化、反序列化能力。

[Serializable]
    internal class Product:ICloneable
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public NumberFlag Number { get; set; }
             //浅拷贝
        public object Clone()
        {
            return this.MemberwiseClone();
        }
     //深拷贝
        public Product DeepClone()
        {
            using (System.IO.Stream ms = new System.IO.MemoryStream())
            {
                System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

                formatter.Context = new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone);

                formatter.Serialize(ms, this);

                ms.Position = 0;

                return formatter.Deserialize(ms) as Product;
            }
        }
    }
    [Serializable]
    internal class NumberFlag
    {
        public string Num { get; set; }
    }

客户端:浅拷贝—引用类型值得改变会相互影响。

Product p1 = new Product()
            {
                Name = "1",
                Age = 1,
                Number = new NumberFlag() { Num="01"}
            };                      

            var p2 = p1.Clone() as Product;

            if (p2 != null)
            {

                p2.Number.Num = "22";

                Console.WriteLine("p1 Number:{0}.",p1.Number.Num);

                Console.WriteLine("p2 Number:{0}.",p2.Number.Num);

                Console.ReadKey();
            }

运行:

客户端:深拷贝—不会有浅拷贝的那种情况。

Product p1 = new Product()
            {
                Name = "1",
                Age = 1,
                Number = new NumberFlag() { Num="01"}
            };                      

            var p2 = p1.DeepClone();

            if (p2 != null)
            {

                p2.Number.Num = "22";

                Console.WriteLine("p1 Number:{0}.",p1.Number.Num);

                Console.WriteLine("p2 Number:{0}.",p2.Number.Num);

                Console.ReadKey();
            }

运行:

 三、建议15:使用dynamic来简化反射实现

这个建议~虽然实例中性能比反射好,但是编译期间跳过验证。运行时才进行类型安全检查。待比较后,才能确定是否使用反射还是dynamic.

时间: 2024-10-06 00:43:05

读改善c#代码157个建议:建议13~15的相关文章

读改善c#代码157个建议:建议4~6

目录: 建议4:TryParse比Parse好 建议5:使用int?确保值类型也可以为null 建议6:区别 readonly 和 const 的用法 一.建议4:TryParse比Parse 好 TryParse:发生转换异常,内部处理异常.返回false并且result=0 public static bool TryParse(string s, out int result); Parse:发生转换异常,会抛出异常. public static decimal Parse(string

读改善c#代码157个建议:建议7~9

目录: 建议7:将0值作为枚举的默认值 建议8:避免给枚举类型的元素提供显示的值 建议9:习惯运算符重载 一.建议7:将0值作为枚举的默认值 允许使用的枚举类型有:byte.sbyte.short.ushort.int.uint.long.ulong. 不指定值,默认从0开始计数,后面的元素依次+1. enum Week { Monday=1, Tuesday=2, Wednessday=3, Thursday=4, Friday=5, Saturday=6, Sunday=7 } 枚举是值类型

读改善c#代码157个建议:建议10~11

目录: 建议10:创建对象时需要考虑是否实现比较器 建议11:区别对待==与Equals 一.建议10:创建对象时需要考虑是否实现比较器 比较一下基本工资: class Salary : IComparable { public string Name { get; set; } public decimal BaseSalary { get; set; } public decimal Bonus { get; set; } public int CompareTo(object obj) {

编写高质量代码改善java程序的151个建议——导航开篇

2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,惨不忍睹是吧.确实,人和代码一样都在成长,都在变好当中.有时候只是实现功能的编程,长进不了呀. 博客提供的好处就可以交流,讨论的学习方法你们应该知道. 在这里,我会陆陆续续的进行对<编写高质量代码改善java程序的151个建议>看法,希望大家点击交流. 正文 看这本书原因   1.项目做的只是实现功能,然而没有好好

转载-------编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)

阅读目录 建议1:不要在常量和变量中出现易混淆的字母 建议2:莫让常量蜕变成变量 建议3:三元操作符的类型务必一致 建议4:避免带有变长参数的方法重载 建议5:别让null值和空值威胁到变长方法              The reasonable man adapts himself to the world; The unreasonable one persists in trying to adapt the world himself. 明白事理的人使自己适应世界:不明事理的人想让世

每周一书-编写高质量代码:改善C程序代码的125个建议

首先说明,本周活动有效时间为2016年8月28日到2016年9月4日.本周为大家送出的书是由机械工业出版社出版,马伟编著的<编写高质量代码:改善C程序代码的125个建议>. 编辑推荐 10余年开发经验的资深C语言专家全面从C语法和C11标准两大方面深入探讨编写高质量C代码的技巧.禁忌和实践 C语言因为既具有高级语言特性,又具有汇编语言特性,所以它是近二十几年来使用较为广泛.生命力较强的编程语言.无论是操作系统.嵌入式系统.普通应用软件,还是移动智能设备开发,它都能够很好地胜任,是公认的强大的语

代码质量优先——《编写高质量代码:改善c程序代码的125个建议》

高质量的代码不但可以促进团队合作.减少bug处理.降低维护成本,对程序员自身的成长也是至关重要的.很难想象一个参考<如何编写无法维护的代码>写代码的程序员技术成长的上限有多么低.为了写出高质量的代码,我们需要听取过来人的改善代码质量的经验,<编写高质量代码:改善c程序代码的125个建议>就是一本能让人写出高质量代码的好书. 本书的第三章<程序控制语句应该保持简洁高效>首先用简练的语言介绍了流程控制结构的概念,然后提供了对if.else.for.do-while.swit

[ 转 ]编写高质量代码:改善Java程序的151个建议

记得3年前刚到公司,同桌同事见我无事可做就借我看<编写高质量代码:改善Java程序的151个建议>这本书,当时看了几页没上心就没研究了.到上个月在公司偶然看到,于是乎又找来看看,我的天,真是非常多的干货,对于我这种静不下心的人真是帮助莫大呀. 看完整本书,也记了不少笔记,我就分享一部分个人觉得有意义的内容,也为了方便以后自己温习. --警惕自增陷阱 i++表示先赋值后自增,而++i表示先自增后赋值.下面的代码返回结果为0,因为lastAdd++有返回值,而返回值是自增前的值(在自增前变量的原始

《编写高质量代码:改善Python程序的91个建议》读后感

编写高质量代码:改善Python程序的91个建议  http://book.douban.com/subject/25910544/ 1.(建议16)is 用于判断两个对象的id是否相等,==才是判断值是否相等 2.(建议23)for,while,和try语句后面都可以跟else语句,可以简化代码 3.(建议18) __init__.py模块可以写代码,import时只需要 import 包(文件夹) 4.(建议19)用import a 而不是 from a import b ,可以避免嵌套导入