当前位置: 移动技术网 > IT编程>开发语言>c# > C#基础概念二十五问 21-25

C#基础概念二十五问 21-25

2019年07月18日  | 移动技术网IT编程  | 我要评论
21.p/invoke是什么?
答:
在受控代码与非受控代码进行交互时会产生一个事务(transition) ,这通常发生在使用平台调用服务(platform invocation services),即p/invoke
如调用系统的 api 或与 com 对象打交道,通过 system.runtime.interopservices 命名空间
虽然使用 interop 非常方便,但据估计每次调用事务都要执行 10 到 40 条指令,算起来开销也不少,所以我们要尽量少调用事务
如果非用不可,建议本着一次调用执行多个动作,而不是多次调用每次只执行少量动作的原则

22.stringbuilder 和 string 的区别?
答:
string 在进行运算时(如赋值、拼接等)会产生一个新的实例,而 stringbuilder 则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用 stringbuilder,不要使用 string
另外,对于 string 我们不得不多说几句:
1.它是引用类型,在堆上分配内存
2.运算时会产生一个新的实例
3.string 对象一旦生成不可改变(immutable)

3.定义相等运算符(== 和 !=)是为了比较 string 对象(而不是引用)的值
示例: 

using system;
using system.collections.generic;
using system.text;
namespace example22
{
    class program
    {
        static void main(string[] args)
        {
            const int cycle = 10000;
            long vtickcount = environment.tickcount;
            string str = null;
            for (int i = 0; i < cycle; i++)
                str += i.tostring();
            console.writeline("string: {0} msel", environment.tickcount - vtickcount);
            vtickcount = environment.tickcount;
            //看到这个变量名我就生气,奇怪为什么大家都使它呢? :)
            stringbuilder sb = new stringbuilder();
            for (int i = 0; i < cycle; i++)
                sb.append(i);
            console.writeline("stringbuilder: {0} msel", environment.tickcount - vtickcount);
            string tmpstr1 = "a";
            string tmpstr2 = tmpstr1;
            console.writeline(tmpstr1);
            console.writeline(tmpstr2);
            //注意后面的输出结果,tmpstr1的值改变并未影响到tmpstr2的值
            tmpstr1 = "b";
            console.writeline(tmpstr1);
            console.writeline(tmpstr2);
            console.readline();
        }
    }
}
结果:
string: 375 msel
stringbuilder: 16 msel
a
a

a

23.explicit 和 implicit 的含义?
答:
explicit 和 implicit 属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换
explicti 表示显式转换,如从 a -> b 必须进行强制类型转换(b = (b)a)
implicit 表示隐式转换,如从 b -> a 只需直接赋值(a = b)
隐式转换可以让我们的代码看上去更漂亮、更简洁易懂,所以最好多使用 implicit 运算符。不过!如果对象本身在转换时会损失一些信息(如精度),那么我们只能使用 explicit 运算符,以便在编译期就能警告客户调用端
示例: 
using system;
using system.collections.generic;
using system.text;
namespace example23
{
    class program
    {
        //本例灵感来源于大话西游经典台词“神仙?妖怪?”--主要是我实在想不出什么好例子了
        class immortal
        {
            public string name;
            public immortal(string name)
            {
                name = name;
            }
            public static implicit operator monster(immortal value)
            {
                return new monster(value.name + ":神仙变妖怪?偷偷下凡即可。。。");
            }
        }
        class monster
        {
            public string name;
            public monster(string name)
            {
                name = name;
            }
            public static explicit operator immortal(monster value)
            {
                return new immortal(value.name + ":妖怪想当神仙?再去修炼五百年!");
            }
        }
        static void main(string[] args)
        {
            immortal tmpimmortal = new immortal("紫霞仙子");
            //隐式转换
            monster tmpobj1 = tmpimmortal;
            console.writeline(tmpobj1.name);
            monster tmpmonster = new monster("孙悟空");
            //显式转换
            immortal tmpobj2 = (immortal)tmpmonster;
            console.writeline(tmpobj2.name);
            console.readline();
        }
    }
}
结果:
紫霞仙子:神仙变妖怪?偷偷下凡即可。。。
孙悟空:妖怪想当神仙?再去修炼五百年! 

24.params 有什么用?
答:
params 关键字在方法成员的参数列表中使用,为该方法提供了参数个数可变的能力
它在只能出现一次并且不能在其后再有参数定义,之前可以
示例:
using system;
using system.collections.generic;
using system.text;
namespace consoleapplication1
{
    class app
    {
        //第一个参数必须是整型,但后面的参数个数是可变的。
        //而且由于定的是object数组,所有的数据类型都可以做为参数传入
        public static void useparams(int id, params object[] list)
        {
            console.writeline(id);
            for (int i = 0; i < list.length; i++)
            {
                console.writeline(list[i]);
            }
        }
        static void main()
        {
            //可变参数部分传入了三个参数,都是字符串类型
            useparams(1, "a", "b", "c");
            //可变参数部分传入了四个参数,分别为字符串、整数、浮点数和双精度浮点数数组
            useparams(2, "d", 100, 33.33, new double[] { 1.1, 2.2 });
            console.readline();
        }
    }
}
结果:
1
a

c
2
d
100
33.33
system.double[] 

25.什么是反射?
答:
反射,reflection,通过它我们可以在运行时获得各种信息,如程序集、模块、类型、字段、属性、方法和事件
通过对类型动态实例化后,还可以对其执行操作
简单来说就是用string可以在runtime为所欲为的东西,实际上就是一个.net framework内建的万能工厂
一般用于插件式框架程序和设计模式的实现,当然反射是一种手段可以充分发挥其能量来完成你想做的任何事情(前面好象见过一位高人用反射调用一个官方类库中未说明的函数。。。)
示例:
using system;
using system.collections.generic;
using system.text;
namespace example25lib
{
    public class class1
    {
        private string name;
        private int age;
        //如果显式的声明了无参数构造函数,客户端只需要用程序集的createinstance即可实例化该类
        //在此特意不实现,以便在客户调用端体现构造函数的反射实现
        //public class1()
        //{
        //}
        public class1(string name, int age)
        {
            name = name;
            age = age;
        }
        public void changename(string newname)
        {
            name = newname;
        }
        public void changeage(int newage)
        {
            age = newage;
        }
        public override string tostring()
        {
            return string.format("name: {0}, age: {1}", name, age);
        }
    }
}
反射实例化对象并调用其方法,属性和事件的反射调用略去
using system;
using system.collections.generic;
using system.text;
//注意添加该反射的命名空间
using system.reflection;
namespace example25
{
    class program
    {
        static void main(string[] args)
        {
            //加载程序集
            assembly tmpass = assembly.loadfile(appdomain.currentdomain.basedirectory + "example25lib.dll");
            //遍历程序集内所有的类型,并实例化
            type[] tmptypes = tmpass.gettypes();
            foreach (type tmptype in tmptypes)
            {
                //获取第一个类型的构造函数信息
                constructorinfo[] tmpconsinfos = tmptype.getconstructors();
                foreach (constructorinfo tmpconsinfo in tmpconsinfos)
                {
                    //为构造函数生成调用的参数集合
                    parameterinfo[] tmpparaminfos = tmpconsinfo.getparameters(); 
                    object[] tmpparams = new object[tmpparaminfos.length];
                    for (int i = 0; i < tmpparaminfos.length; i++)
                    {
                        tmpparams[i] = tmpass.createinstance(tmpparaminfos[i].parametertype.fullname);
                        if (tmpparaminfos[i].parametertype.fullname == "system.string")
                        {
                            tmpparams[i] = "clark";
                        }
                    }
                    //实例化对象
                    object tmpobj = tmpconsinfo.invoke(tmpparams);
                    console.writeline(tmpobj);
                    //获取所有方法并执行
                    foreach (methodinfo tmpmethod in tmptype.getmethods())
                    {
                        //为方法的调用创建参数集合
                        tmpparaminfos = tmpmethod.getparameters();
                        tmpparams = new object[tmpparaminfos.length];
                        for (int i = 0; i < tmpparaminfos.length; i++)
                        {
                            tmpparams[i] = tmpass.createinstance(tmpparaminfos[i].parametertype.fullname);
                            if (tmpparaminfos[i].parametertype.fullname == "system.string")
                            {
                                tmpparams[i] = "clark zheng";
                            }
                            if (tmpparaminfos[i].parametertype.fullname == "system.int32")
                            {
                                tmpparams[i] = 27;
                            }
                        }
                        tmpmethod.invoke(tmpobj, tmpparams);
                    }
                    //调用完方法后再次打印对象,比较结果
                    console.writeline(tmpobj);
                }
            }
            console.readline();
        }
    }
}
结果:
name: clark, age: 0
name: clark zheng, age: 27
来自:

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网