C#拾遗系列(9):继承、接口、扩展方法、分部类、类操作、Ref and Out、可空类型
2008-06-19 15:07 敏捷的水 阅读(1355) 评论(1) 编辑 收藏 举报本文内容:
- 继承
- 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);
}
}
}
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 Happy: IJack,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
版权:本文版权归作者所有,转载需经作者同意。