C#基础-第5章:基元类型、引用类型和值类型
2021-06-22 10:05
标签:math generic amp false 部分 [] eof efault form 5 本章内容: PS:以下代码以装箱和拆箱的说明居多 C#基础-第5章:基元类型、引用类型和值类型 标签:math generic amp false 部分 [] eof efault form 原文地址:https://www.cnblogs.com/eric-yuan/p/10218599.html
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Dynamic;
using System.Linq;
using Microsoft.CSharp.RuntimeBinder;
///////////////////////////////////////////////////////////////////////////////
public static class Program
{
public static void Main()
{
PrimitiveDemo();
BoxingDemo();
ReferenceVsValue.Go();
Boxing.Go();
BoxingForInterfaceMethod.Go();
MutateViaInterface.Go();
DynamicDemo.Go();
}
private static void PrimitiveDemo()//P99-100
{
//以下4行都能正确的编译,并生成相同的IL代码
int a = new int(); //不方便的语法
int b = 0; //最方便的语法
System.Int32 c = new System.Int32(); //最不方便的语法
Int32 d = 0; //方便的语法 Int32 int 是等价的
// 显示全部变量为0
Console.WriteLine("a = {0}, b = {1}, c = {2}, d = {3}",
new Object[] { a, b, c, d });
// 设置全部的值为5
a = b = c = d = 5;
Console.WriteLine("a = {0}, b = {1}, c = {2}, d = {3}",
new Object[] { a, b, c, d });
}
private static void BoxingDemo()
{
Int32 a = 5; // 创建未装箱的值类型变量
Object o = a; // o引用已装箱的a的版本
a = 123; // 修改未装箱的值 123
Console.WriteLine(a + ", " + (Int32)o); // 显示 "123, 5"
Console.WriteLine(a + ", " + o); // 优化
Console.WriteLine(a); // 没有装箱
}
//引用类型vs值类型
private static class ReferenceVsValue
{
//引用类型 (因为 ‘class‘)
private class SomeRef { public Int32 x; }
// 值类型 (因为 ‘struct‘)
private struct SomeVal { public Int32 x; }
public static void Go()//P(107)
{
SomeRef r1 = new SomeRef(); // 在堆上分配
SomeVal v1 = new SomeVal(); // 在栈是分类
r1.x = 5; // 提领指针
v1.x = 5; // 在栈上修改
Console.WriteLine(r1.x); // 显示 "5"
Console.WriteLine(v1.x); // 同样显示 "5"
//图5-2的左半部分反映了执行以上代码之后的情况
SomeRef r2 = r1; // 只复制应用(指针)
SomeVal v2 = v1; // 在栈上分配并复制成员
r1.x = 8; // r1.x 和 r2.x 都会改变
v1.x = 9; // v1.x 会变, v2.x 不变
Console.WriteLine(r1.x); // 显示 "8"
Console.WriteLine(r2.x); // 显示 "8"
Console.WriteLine(v1.x); // 显示 "9"
Console.WriteLine(v2.x); // 显示 "5"
//图5-2的右半部分反映了执行以上所有代码之后的情况
}
}
private static class Boxing
{
public static void Go()//P(111)
{
ArrayList a = new ArrayList();
Point p; //分配一个Point(不在堆中分配).
for (Int32 i = 0; i 10; i++)
{
p.x = p.y = i; // 初始化值类型中的成员
a.Add(p); // 对值的类型装箱,将引用添加到ArrayLis中
}
}
// 声明一个值类型
private struct Point { public Int32 x, y; }
public static void Main2()//P(113)
{
Int32 x = 5;
Object o = x; // 对x装箱,o引用已装箱对象
Int16 y = (Int16)o; // 抛出 InvalidCastException 异常
}
public static void Main3()//P(113)
{
/* Main2 方法正确的转化方式 */
Int32 x = 5;
Object o = x; // 对x进行装箱,o引用已装箱对象
Int16 y = (Int16)(Int32)o; // 先拆箱为正确类型,再转型
}
public static void Main4()
{
Point p;
p.x = p.y = 1;
Object o = p; //对P进行装箱
p = (Point)o; //对o进行拆箱,将字段从已装箱实例复制到栈变量中
}
public static void Main5()
{
Point p;
p.x = p.y = 1;
Object o = p; // 对p进行装箱;o引用已装箱的实例
// 将 Point的字段变成2
p = (Point)o; // 对o拆箱,将字段从已装箱的实例复制到栈变量中
p.x = 2; // 更改栈变量的状态
o = p; // 对p装箱;o引用新的已装箱实例
}
public static void Main6()//P(114)
{
Int32 v = 5; // 创建未装箱值类型变量
Object o = v; // o引用已装箱的,包含值5的Int32
v = 123; // 改变为装箱的的值改成123
Console.WriteLine(v + ", " + (Int32)o); // 显示 "123, 5"
}
public static void Main7()//P(116)
{
Int32 v = 5; // 创建未装箱值类型变量.
Object o = v; // o 引用v的已装箱版本
v = 123; //将未装箱的值类型修改成123
Console.WriteLine(v); // 显示 "123"
v = (Int32)o; //拆箱并将o复制到v
Console.WriteLine(v); // 显示 "5"
}
public static void Main8()//P(117)
{
Int32 v = 5; // 创建未装箱的值类型变量
#if INEFFICIENT
// 编译下面这一行,v 被装箱3次,浪费时间和内存
Console.WriteLine("{0}, {1}, {2}", v, v, v);
#else
// 下面的代码结果一样,但无论执行速度,
// 还是内存利用,都比前面的代码更胜一筹
Object o = v; // 对v手动装箱(仅一次)
// 编译下面这一行不发生装箱
Console.WriteLine("{0}, {1}, {2}", o, o, o);
#endif
}
}
private static class BoxingForInterfaceMethod
{
private struct Point : IComparable //p(118)
{
private Int32 m_x, m_y;
//构造器负责初始化字段
public Point(Int32 x, Int32 y)
{
m_x = x;
m_y = y;
}
//重写从System.ValueType 继承的ToString方法
public override String ToString()
{
//如果调用了 base.ToString() 则会被装箱
//将point做字符串返回。注意:调用ToString以避免装箱
return String.Format("({0}, {1})", m_x, m_y);
}
// 实现类型安全的CompareTo方法
public Int32 CompareTo(Point other)
{
// 利用勾股定理计算哪个point距离原点(0,0)更远
return Math.Sign(Math.Sqrt(m_x * m_x + m_y * m_y)
- Math.Sqrt(other.m_x * other.m_x + other.m_y * other.m_y));
}
// 实现IComparable 的 CompareTo 方法
public Int32 CompareTo(Object o)
{
if (GetType() != o.GetType())
{
throw new ArgumentException("o is not a Point");
}
// 调用类型安全的ComareTo方法
return CompareTo((Point)o);
}
}
public static void Go() //P(119)
{
// 在栈上创建2个Point的实例
Point p1 = new Point(10, 10);
Point p2 = new Point(20, 20);
// 调用ToString(虚方法)不装箱p1;
Console.WriteLine(p1.ToString()); // 显示"(10, 10)"
// 调用GetType(非虚方法)时,要对P1进行装箱
Console.WriteLine(p1.GetType()); // 显示"Point"
//调用CompareTo 不装箱p1
//由于调用的是CompareTo(Point),所以p2不装箱
Console.WriteLine(p1.CompareTo(p2)); // "-1"
// p1要装箱,引用放到c中
IComparable c = p1;
Console.WriteLine(c.GetType()); // 显示"Point"
//调用CompareTo不装箱p1
//由于CompareTo传递不是Point变量
//所以调用的是CompareTo(Object),它要求获取对装箱Point的引用
//c不装箱是因为本来就引用了已装箱Point
Console.WriteLine(p1.CompareTo(c)); // 显示"0"
// c不装箱,因为它本来就引用了已装箱Point
// p2要装箱,因为调用的是CompareTo(Object)
Console.WriteLine(c.CompareTo(p2)); // "-1"
//对c拆箱,字段复杂到P2中
p2 = (Point)c;
// 证明字段已复制到P2中
Console.WriteLine(p2.ToString()); // "(10, 10)"
}
}
private static class MutateViaInterface
{
// 接口定义了Change方法
private interface IChangeBoxedPoint
{
void Change(Int32 x, Int32 y);
}
// Point是值类型.
private struct Point : IChangeBoxedPoint
{
private Int32 m_x, m_y;
public Point(Int32 x, Int32 y)
{
m_x = x;
m_y = y;
}
public void Change(Int32 x, Int32 y)
{
m_x = x; m_y = y;
}
public override String ToString()
{
return String.Format("({0}, {1})", m_x, m_y);
}
}
public static void Go()
{
Point p = new Point(1, 1);
Console.WriteLine(p);
p.Change(2, 2);
Console.WriteLine(p);
Object o = p;
Console.WriteLine(o);
((Point)o).Change(3, 3);
Console.WriteLine(o);
// 对p进行装箱,更改已装箱的对象,然后丢弃它
((IChangeBoxedPoint)p).Change(4, 4);
Console.WriteLine(p);
// 更改已装箱的的对戏,并显示它
((IChangeBoxedPoint)o).Change(5, 5);
Console.WriteLine(o);
/********************* 如果把Point 改成class 引用类型 就不存在装箱,拆箱的的转化,上面的结果就会发变化 ********************/
}
}
private static class DynamicDemo
{
public static void Go()
{
ShowLoadedAssemblies("Assemblies loaded before use of dynamic");
SimpleDynamic();
ShowLoadedAssemblies("Assemblies loaded after simkple use of dynamic");
Demo();
ShowLoadedAssemblies("Assemblies loaded after all dynamic code runs");
ExcelAutomation();
DynamicStaticInvocations();
}
private static void ShowLoadedAssemblies(String caption)
{
Console.WriteLine(caption);
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
Console.WriteLine(" " + a.GetName().Name);
Console.WriteLine();
}
private static Int32 SimpleDynamic()
{
return ((dynamic)0) + 0;
}
private static void Demo() //P(129)
{
dynamic value;
for (Int32 demo = 0; demo 2; demo++)
{
value = (demo == 0) ? (dynamic)5 : (dynamic)"A";
value = value + value;
M(value);
}
Object o = 123; // OK: 从Int32 隐形转型为Object(装箱)
//Int32 n1 = o; // Error: 不允许从Object到Int32的隐式转化
Int32 n2 = (Int32)o; // OK: 从Object显示转型为Int32(拆箱)
dynamic d = 123; // OK: 从 Int32 隐形转化为 dynamic(装箱)
Int32 n3 = d; // OK: 从 dynamic 隐式转为 Int32(拆箱)
try
{
var m = M(d); // 注意: ‘var m‘ 等同于 ‘dynamic m‘
}
catch (RuntimeBinderException) { }
var x = (Int32)d; // ‘var x‘ 等同于 ‘Int32 x‘
var dt = new DateTime(d); // ‘vat dt‘ 等同于 ‘DateTime dt‘
}
private static void M(Int32 n) { Console.WriteLine("M(Int32): " + n); }
private static void M(String s) { Console.WriteLine("M(String): " + s); }
///
文章标题:C#基础-第5章:基元类型、引用类型和值类型
文章链接:http://soscw.com/index.php/essay/97327.html