C#拾遗系列(9):继承、接口、扩展方法、分部类、类操作、Ref and Out、可空类型

简介:

本文内容:

  • 继承
  • Equal示例
  • 结构和类
  • 属性
  • Ref and Out
  • 类操作
  • 扩展方法
  • 接口
  • 可空类型
  • 分部类

 

1. 继承

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace NetTest

{

    public class Animal

    {

        public virtual void Fly()

        {

            Console.Out.WriteLine("Animal Fly");

            Console.Out.WriteLine("----------------------------");

        }

    }

    public class Dog : Animal

    {

        public new virtual void Fly()

        {

            base.Fly();

            Console.Out.WriteLine("Dog  can't Fly");

            Console.Out.WriteLine("----------------------------");

        }

        //也可以,但子类不能再覆盖了

        //public new  void Fly()

        //{

        //    base.Fly();

        //    Console.Out.WriteLine("Dog can't Fly");

        //    Console.Out.WriteLine("----------------------------");

        //}               

    }

    public class Cat : Animal

    {

        public override void Fly()

        {

            base.Fly();

            Console.Out.WriteLine("Cat can't fly");

            Console.Out.WriteLine("----------------------------");

        }

 

        public override string ToString()

        {

            return "I am a happy cat,wow";

        }

 

    }

 

    public class InheritTest

    {

        public void Test()

        {

            /*

           new 和 overide的区别是,当把子类付给父类变量时,new 将调用父类的方法,而override将调用子类的方法       

           */

            Animal dog = new Dog();

            dog.Fly();

            /* 输出

            Animal Fly   

            */

 

            Animal cat = new Cat();

            cat.Fly();

 

            /* 输出

            Animal fly

            Cat can't Fly           

            */

            Console.Out.WriteLine(cat.ToString());

 

        }

    }

}

 

2. Equal 示例

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

    public class EqualsTest

    {

        public void testEquals()

        {

            /*C# 中有两种不同的相等:引用相等和值相等。

            值相等是大家普遍理解的意义上的相等:

            它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。

            引用相等意味着要比较的不是两个对象,而是两个对象引用,且两者引用的是同一个对象                    

            若要检查引用相等性,应使用 ReferenceEquals。若要检查值相等性,请使用 Equals。           

            */

            object a = new object();

            object b = a;

            Console.Out.WriteLine(System.Object.ReferenceEquals(b, a));

 

            int c = 2;

            int d = 3;

            Console.Out.WriteLine(c.Equals(d));           

        }

    }

}

 

 

3.  结构和类

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

/*   

    结构具有以下特点:结构是值类型,而类是引用类型。

    与类不同,结构的实例化可以不使用 new 运算符。  

    结构可以声明构造函数,但它们必须带参数。      

    一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType,后者继承自 System.Object。

    结构可以实现接口。                                                                                              

    结构可用作可为 null 的类型,因而可向其赋 null 值。                                                      

*/ 

namespace NetTest

{

    struct StructAndClass

    {

        /*

        * 结构不能包含无参构造函数

        public StructAndClass(){ }

        */

 

        public StructAndClass(int age, string name)

        {

            this.age = age;

            this.name = "jack";

        }

        public int age;

        public string name;

    }

   public class TestStrcutAndClass

    {

        public void TestSAC()

        {

            StructAndClass a = new StructAndClass();

            a.age = 10;

            a.name = "jack";

            Console.Out.WriteLine(a.age + ":" + a.name);

            StructAndClass b = new StructAndClass(20, "wang");

            Console.Out.WriteLine(b.age + ":" + b.name);

        }

    }

}

 

4. 属性

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

    public class TestAttribute

    {

        public void Test()

        {           

            PrintAuthorInfo(typeof(CustomAttribute));       

        }

 

        /*

        Obsolete 属性将某个程序实体标记为一个建议不再使用的实体。每次使用被标记为已过时的实体时,

        随后将生成警告或错误,这取决于属性是如何配置的,第二个参数是true时,编译时显示错误

        */

        [Obsolete("please use aonther method,this is obsolate",true)]

        public void TestObsolate()

        {

            Console.Out.WriteLine("welcome");

 

        }

        private static void PrintAuthorInfo(System.Type t)

        {

            System.Console.WriteLine("Author information for {0}", t);

            System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // reflection

 

            foreach (System.Attribute attr in attrs)

            {

                if (attr is Author)

                {

                    Author a = (Author)attr;

                    System.Console.WriteLine("   {0}, version {1:f}", a.Name, a.version);

                }

            }

        }

        //应用自定义属性

        [Author("Jack",version=1.0)]

        [Author("TJ",version=2.0)]

        class CustomAttribute

        {

            public void Test()

            {

 

                Console.Out.WriteLine("Test custom attribute");

            }       

        }

        //自定义的属性,集成属性类

        [System.AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct,AllowMultiple=true)]

        class Author : System.Attribute

        {

            private string name;

            public double version;

 

            public Author(string name)

            {

                this.name = name;

                version = 1.0;

            }

 

            public string Name

            {

 

                get { return this.name; }

            }

 

        }

    }

 

}

 

5. Ref and Out

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

   public  class TestRefOut

    {

       private Shape s;

       private Shape d;

 

       /* 传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化 ,out 必须在方法内部赋值

       尽管 ref 和 out 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,

       而另一个方法采用 out 参数,则无法重载这两个方法

        属性不是变量,因此不能作为 ref 参数传递

        */

       private void Test(ref Shape a, out Shape b)

       {

           //a = "good";

           b = new Shape();

           b.width = 500;

           Console.Out.WriteLine(a.width);

       }

       public void Test()

       {

           s = new Shape();

           s.width = 200;

           Test( ref s, out d);

           Console.Out.WriteLine(d.width);

 

       }

    }

 

   public class Shape

   {

       public int width;

       public int length;

   }

}

 

6. 类操作

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

   public class OperationOveride

    {

       public void TestOperationOverid()

       {

           Complex c1 = new Complex(10, 2);

           Complex c2 = new Complex(5, 4);

           Complex c3 = c1 + c2;

           Console.Out.WriteLine(c3.real + "," + c3.imaginary);       

       }      

    }

 

    public struct Complex

    {

        public int real;

        public int imaginary;

 

        public Complex(int real, int image)

        {

            this.real = real;

            this.imaginary = image;

        }

 

        public static Complex operator +(Complex c1, Complex c2)

        { 

            return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);

        }

 

    }

}

 
7. 扩展方法
 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

//Description: 扩展方法

namespace NetTest

{

    public class TestExtendMethod

    {

        public void Test()

        {

            Jack my = new Jack();

            my.showSmile();

            int i = 5;

            Console.Out.WriteLine(i.addAge(10));

 

        }

    }

    public class Jack

    {

        public void Smile()

        {

            Console.Out.WriteLine("Jack smile");

        }

    }

 

    /*

    扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。

    扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。

    对于用 C# 和 Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异.     

 

    在代码中,可以使用实例方法语法调用该扩展方法。但是,编译器生成的中间语言 (IL) 会将代码转换为对静态方法的调用。

    因此,并未真正违反封装原则。实际上,扩展方法无法访问它们所扩展的类型中的私有变量。

 

    可以使用扩展方法来扩展类或接口,但不能重写扩展方法。与接口或类方法具有相同名称和签名的扩展方法永远不会被调用。

    编译时,扩展方法的优先级总是比类型本身中定义的实例方法低。换句话说,

    如果某个类型具有一个名为 Process(int i) 的方法,而您有一个具有相同签名的扩展方法,则编译器总是绑定到该实例方法。

    当编译器遇到方法调用时,它首先在该类型的实例方法中寻找匹配的方法。

    如果未找到任何匹配方法,编译器将搜索为该类型定义的任何扩展方法,并且绑定到它找到的第一个扩展方法。

 

    */

    public static class myExtendmethod

    {

        public static void showSmile(this Jack jack)

        {

            Console.Out.WriteLine("This is Extend method");

        }

 

        public static int addAge(this int s, int b)

        {

            return s + b;

        }

 

    }

 

}

 

8. 接口

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

   public  interface IJack

    {

        void Happy();

 

    }

 

   public interface ICrystal

    {

        void Happy();

    }

 

   public class HappyIJack,ICrystal

    {

        #region IJack Members

 

        //不能用限定符如private ,public等

        void IJack.Happy()

        {

            Console.Out.WriteLine("haha");

        }

        #endregion

 

        #region ICrystal Members

 

       //显示实现的成员不能从类直接访问

        void ICrystal.Happy()

        {

            Console.Out.WriteLine("smile");

        }

 

        #endregion 

 

    }

 

   public class TestInterface

   {

       public void Test()

       {

           /*

            同名时,必须转换到接口才能调用,两个方法实现都是分离的,都不可以直接在类中使用

            */

 

           /*

           Happy t = new Happy();   //显示实现的成员不能从类直接访问

           t.(..)

            * */

 

           IJack testHappy =(IJack)new Happy();

 

           testHappy.Happy();

 

           ICrystal testcrystalHappy = (ICrystal)new Happy();

           testcrystalHappy.Happy();

       }

   }

}

 

 

9. 可空类型

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

    public  class TestNullable

    {

        public void Test()

        {

            IsNullValue(null);

            IsNullValue(20);

            int? c = null;

 

            //?? 运算符定义在将可以为 null 的类型分配给非可以为 null 的类型时返回的默认值

            int d = c ?? -1;

            Console.Out.WriteLine(d);

 

        }

 

        public void IsNullValue(int? num)

        {

           if (num.HasValue)

            {

                System.Console.Out.WriteLine("num has value:" + num);

                System.Console.Out.WriteLine("num  vaue has value:" + num.Value);

            }

            else

            {

                System.Console.Out.WriteLine("num is null" );

            }

           System.Console.Out.WriteLine(num.GetValueOrDefault());

           System.Console.Out.WriteLine(num.GetValueOrDefault(100));

           System.Console.Out.WriteLine("---------------------");

        }

    }

}

 

 

10. 分部类

  a. 描述:

        分部类或结构可以包含分部方法。类的一个部分包含方法的签名。可以在同一部分或另一个部分中定义可选实现。

        如果未提供该实现,则会在编译时移除方法以及对方法的所有调用。

        分部方法使类的某个部分的实施者能够定义方法(类似于事件)。

        类的另一部分的实施者可以决定是否实现该方法。如果未实现该方法

        编译器将移除方法签名以及对该方法的所有调用。因此,分部类中的任何代码都可以随意地使用分部方法,

        即使未提供实现也是如此。如果调用了未实现的方法,将不会导致编译时错误或运行时错误。

 

        在自定义生成的代码时,分部方法特别有用。这些方法允许保留方法名称和签名,

        因此生成的代码可以调用方法,而开发人员可以决定是否实现方法。

        与分部类非常类似,分部方法使代码生成器创建的代码和开发人员创建的代码能够协同工作,而不会产生运行时开销。

        分部方法声明由两个部分组成:定义和实现。它们可以位于分部类的不同部分中,

        也可以位于同一部分中。如果不存在实现声明,则编译器将优化定义声明和对方法的所有调用。

 

        分部方法声明必须以上下文关键字 partial 开头,并且方法必须返回 void。

        分部方法可以有 ref 参数,但不能有 out 参数。

        分部方法为隐式 private 方法,因此不能为 virtual 方法。

        分部方法不能为 extern 方法,因为主体的存在确定了方法是在定义还是在实现。

        分部方法可以有 static 和 unsafe 修饰符。

        分部方法可以为泛型的。约束将放在定义分部方法声明上,但也可以选择重复放在实现声明上。

        参数和类型参数名称在实现声明和定义声明中不必相同。

        不能将委托转换为分部方法。         

   b. 示例:

     

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace NetTest

{

    /*

    可以将类或结构、接口或方法的定义拆分到两个或多个源文件中。

    每个源文件包含类型或方法定义的一部分,

    编译应用程序时将把所有部分组合起来   

 

    partial 修饰符不可用于委托或枚举声明中。

 

    将从所有分部类型定义中对以下内容进行合并:

    XML 注释

    接口

    泛型类型参数属性

    类属性

    成员   

    */

    public partial interface Chicken

    {

        void run();

    };

 

    public partial interface Chicken

    {

        void walk();

    }

 

    public class smallChicken : Chicken

    {

        #region Chicken Members

 

        public void run()

        {

            Console.Out.WriteLine("small chicken run..");

        }

 

        public void walk()

        {

            Console.Out.WriteLine("small chicken walk");

        }

 

        #endregion

    }

 

    public partial class TestPartial

    {

        public void TestA() { Console.Out.WriteLine("TestA"); }

 

        // Definition

        partial void onNameChanged();

 

    }

 

    public partial class TestPartial

    {

        public void TestB() { Console.Out.WriteLine("TestB"); }

        // Implementation

                partial void onNameChanged()

        {

            Console.Out.WriteLine("partial method");

        }

 

    }

 

    public partial class TestpartialCall

    {

 

        public void Test()

        {

            TestPartial test = new TestPartial();

            test.TestA();

            test.TestB();

 

            Chicken smallChicken=new smallChicken();

            smallChicken.run();

            smallChicken.walk();

 

        }

    }

}

本文转自敏捷的水博客园博客,原文链接http://www.cnblogs.com/cnblogsfans/archive/2008/06/19/1225961.html如需转载请自行联系原作者


王德水

相关文章
|
2月前
|
开发框架 .NET C#
C#|.net core 基础 - 删除字符串最后一个字符的七大类N种实现方式
【10月更文挑战第9天】在 C#/.NET Core 中,有多种方法可以删除字符串的最后一个字符,包括使用 `Substring` 方法、`Remove` 方法、`ToCharArray` 与 `Array.Copy`、`StringBuilder`、正则表达式、循环遍历字符数组以及使用 LINQ 的 `SkipLast` 方法。
|
3月前
|
存储 C# 索引
C# 一分钟浅谈:数组与集合类的基本操作
【9月更文挑战第1天】本文详细介绍了C#中数组和集合类的基本操作,包括创建、访问、遍历及常见问题的解决方法。数组适用于固定长度的数据存储,而集合类如`List<T>`则提供了动态扩展的能力。文章通过示例代码展示了如何处理索引越界、数组长度不可变及集合容量不足等问题,并提供了解决方案。掌握这些基础知识可使程序更加高效和清晰。
93 2
|
15天前
|
开发框架 监控 .NET
C#进阶-ASP.NET WebForms调用ASMX的WebService接口
通过本文的介绍,希望您能深入理解并掌握ASP.NET WebForms中调用ASMX WebService接口的方法和技巧,并在实际项目中灵活运用这些技术,提高开发效率和应用性能。
33 5
|
1天前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(24年12月更新)
C#/.NET/.NET Core拾遗补漏合集(24年12月更新)
|
1月前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
38 3
|
1月前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
63 1
|
1月前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
18 0
|
2月前
|
C#
C# 可空类型(Nullable)
C# 单问号 ? 与 双问号 ??
62 12
|
2月前
|
C#
C# 接口(Interface)
接口定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分。 接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。 接口使得实现接口的类或结构在形式上保持一致。 抽象类在某种程度上与接口类似,但是,它们大多只是用在当只有少数方法由基类声明由派生类实现时。 接口本身并不实现任何功能,它只是和声明实现该接口的对象订立一个必须实现哪些行为的契约。 抽象类不能直接实例化,但允许派生出具体的,具有实际功能的类。
52 9
|
2月前
|
Java 程序员 C#
【类的应用】C#应用之派生类构造方法给基类构造方法传参赋值
【类的应用】C#应用之派生类构造方法给基类构造方法传参赋值
16 0