黑马程序员-console.writeline,不定长参数以及params

------- Windows Phone 7手机开发.Net培训、期待与您交流! -------

console.writeline()有一个重载是这样的:

public static void WriteLine(string format, params object[] arg);

百度params,进一步得出答案:

arams 构造函数声明数组 而不知道数组长度 用的
在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。

形如:
using System;
public class MyClass 
{
    public static void UseParams(params object[] list) 
    {
        for (int i = 0 ; i < list.Length; i++)
        {
            Console.WriteLine(list[i]);
        }
        Console.WriteLine();
    }

params参数允许数组在运行时确定长度

也就是说wirteline函数这个重载把N个参数都放进一个数组中,不过数组的长度是多少,然后根据format中占位符的数量把数组中的参数读取出来

然而问题又来了,后面的数组中的数据类型是不同的,程序怎么知道要读取的变量在内存中有多长呢?

答案是显然的,函数把所有的变量都打包成了object类型,而object类型是所有类型的子类

再继续深挖下去,object类型是固定长度的吗?于是我们的新问题就变成了,object类型在底层的具体实现是什么样的?


笔者先不给出答案,笔者想到C语言中函数的一种写法:

void func(char *str,...);

这个...不是我故意省略了,而是真的可以写成"..."(必须是3个点)

这代表编译器不检查第一个参数后面参数的类型和个数,而读取参数的工作交给程序员来完成

具体读取的过程大概是这样的:

声明一个字符指针(因为C语言中字符指针的偏移量是1个字节)指向字符串str的末尾(也就是后面一个参数的开始)

按字符读取str串,比如这个串是“dcs”,读取到第一个字符d

这时进入一个switch循环中:

 ...

case d:

printf("%d",p);//读取一个整形变量那么长然后输出,假设我们这个函数的实现是输出不定长个变量

p+=sizeof(int);//p是刚才那个字符指针,偏移4个字节,指向下一个变量的开始

break;

...

然后读取第二个字符c,c表示读取一个char类型,指针偏移 加1个字节,指向第三个变量

第三个是s,表示读取一个字符串,指针一直加1直到遇见"\0"结束标记

如果前面串中还有字符,就依次类推。

这种读取方式基于一个假定的事实,所有的参数在内存中都是连续储存的,如果不连续,就无法确定偏移量是多少

我们再回到C#中来,思考一下object类型:

笔者推测出,object类型实际上封装了一个指针,和一个说明参数类型的字节(也可能是多个字节,但总之这个说明占用的长度是固定的)

指针的大小也是固定的4个字节,所以所有的object都有统一大小,而由其生成子类型的方式,其实是根据指针指向了内存中那个子类型变量的区域

那么你们还能提出更多问题吗,比如拆箱和装箱?留给你们去思考吧,嘿嘿

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
using System; using System.Collections.Generic; public class PlaylistApp { public static void Main(string[] args) { LinkedList<string> playlist = new LinkedList<string>(); Stack<string> history = new Stack<string>(); Scanner scanner = new Scanner(System.in); while (true) { Console.WriteLine("Choose an option:"); Console.WriteLine("1. Add a song to your playlist"); Console.WriteLine("2. Play the next song in your playlist"); Console.WriteLine("3. Skip the next song"); Console.WriteLine("4. Rewind one song"); Console.WriteLine("5. Exit"); string input = scanner.nextLine(); if (input.Equals("1")) { Console.WriteLine("Enter Song Name:"); string song = scanner.nextLine(); playlist.AddLast(song); Console.WriteLine(""" + song + "" added to your playlist."); } else if (input.Equals("2")) { if (playlist.Count > 0) { string song = playlist.RemoveFirst(); history.Push(song); Console.WriteLine("Now playing "" + song + """); if (playlist.Count > 0) { Console.WriteLine("Next song: "" + playlist.First.Value + """); } else { Console.WriteLine("Next song: none queued"); } } else { Console.WriteLine("Your playlist is empty."); } } else if (input.Equals("3")) { if (playlist.Count > 0) { string song = playlist.RemoveFirst(); Console.WriteLine("Skipped "" + song + """); if (playlist.Count > 0) { Console.WriteLine("Next song: "" + playlist.First.Value + """); } else { Console.WriteLine("Next song: none queued"); } } else { Console.WriteLine("Your playlist is empty."); } } else if (input.Equals("4")) { if (history.Count > 0) { string song = history.Pop(); //JAVA TO C# CONVERTER TASK: There is no .NET LinkedList equivalent to the 2-parameter Java 'add' method: playlist.add(0, song); Console.WriteLine("Rewound to "" + song + """); if (playlist.Count > 0) { Console.WriteLine("Next song: "" + playlist.First.Value + """); } else { Console.WriteLine("Next song: none queued"); } } else { Console.WriteLine("You haven't played any songs yet."); } } else if (input.Equals("5")) { Console.WriteLine("Goodbye!"); break; } else { Console.WriteLine("Invalid input."); } } scanner.close(); } } 修改代码
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值