C#学习(8)----方法参数

一、传值参数

前面没有修饰符

就是C里边的形参。普普通通,没啥可说。

会创建副本,占用存储位置。

有一点要注意。值类型的变量存储的是数值;但是引用变量存储的是对象的地址,所以如果对传值参数的引用变量操作,是会改变该对象的。但是如果对传值参数赋值一个新对象的地址,原来的实参牵着的对象不会改变。

例子:

//输出结果:10 100 100,主函数的stu所指的对象在调用方法后成员改变。
//两者的hashcode相同。
namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            Student stu = new Student();
            stu.Age = 10;
            Console.WriteLine(stu.Age);
            Student.haha(stu);
            Console.WriteLine(stu.Age);
            Console.WriteLine(stu.GetHashCode());
        }
    }

    class Student
    {
        private int age;

        public int Age
        {
            get { return age; }
            set { age = value; }
        }

        public static void haha(Student stu)
        {
            stu.age = 100;
            Console.WriteLine(stu.age);
            Console.WriteLine(stu.GetHashCode());
        }
    }
}
//输出结果:10 100 10
//hashcode里面外面不一样,且差别较大:46104728  12289376
namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            Student stu = new Student();
            stu.Age = 10;
            Console.WriteLine(stu.Age);
            Student.haha(stu);
            Console.WriteLine(stu.Age);
            Console.WriteLine(stu.GetHashCode());
        }
    }

    class Student
    {
        private int age;

        public int Age
        {
            get { return age; }
            set { age = value; }
        }

        public static void haha(Student stu)
        {
            Console.WriteLine(stu.GetHashCode());
            stu = new Student();
            stu.age = 100;
            Console.WriteLine(stu.GetHashCode());
            Console.WriteLine(stu.age);
        }
    }
}

但实际上,例1这种修改了实参对象,这种结果常常被叫作方法的副作用。平时应该尽量避免。

二、引用参数

ref修饰符

引用参数不创造新的存储位置,他直接表示实参的那个变量所表示的对象存储位置。

变量在可以作为引用形参传递之前,必须先明确赋值!!

//对于值类型:相当于C语言的指针
namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            int x = 100;
            haha(ref x);
            Console.WriteLine(x);
            
        }
        static void haha(ref int x)
        {
            x = 10;
        }
    }
}
//对于引用类型,不改变牵着的对象,改变对象成员
namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            Student stu = new Student() { Age = 10 };
            IWantSideeffect(ref stu);//此处要写上ref,显式告诉编译器,我就是要改
            Console.WriteLine(stu.Age);
        }
        
        static void IWantSideeffect(ref Student stu)//感觉老师这个名字写的很好玩于是就搬了过来www
        {
            stu.Age = 100;
        }
    }

    class Student
    {
        private int age;

        public int Age
        {
            get { return age; }
            set { age = value; }
        }

    }
}
//对于引用类型,直接覆盖一个新的对象
/*
输出结果:
10,46104728
10,46104728
100,12289376
100,12289376
显然实参也被改变了。这点可看出引用类型与值类型效果不同。
*/
namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            Student stu = new Student() { Age = 10 };
            Console.WriteLine("{0},{1}", stu.Age, stu.GetHashCode());
            IWantSideeffect(ref stu);
            Console.WriteLine("{0},{1}", stu.Age, stu.GetHashCode());
        }
        static void IWantSideeffect(ref Student stu)
        {
            Console.WriteLine("{0},{1}",stu.Age,stu.GetHashCode());
            stu = new Student() { Age = 100 };
            Console.WriteLine("{0},{1}", stu.Age, stu.GetHashCode());
        }
    }

    class Student
    {
        private int age;
        public int Age
        {
            get { return age; }
            set { age = value; }
        }
    }
}

三、输出参数

out修饰符

输出参数不会创造变量的副本,所以没有占用新的存储空间。

使用out修饰符显式表示,该方法副作用是向外界变量输出值。

out参数要求一定在各种分支都要有输出。

out参数给予的那个实参之前可以没值。

ref更倾向于改变,out倾向于输出。

//输出类型对于值类型:
    class Program
    {
        static void Main()
        {
            int x = -100, y = 10,result;
            result = 100;//如果不成功,result原本的值会被覆盖
            bool isSuccess = OutPut(out result, x, y);
            Console.WriteLine("{0},{1}",result,isSuccess);
        }
        static bool OutPut(out int result,int x,int y)
        {
            if (x + y > 0)
            {
                result = x + y;
                return true;
            }
            else
            {
                result = 0;
                return false;
            }
        }

不过其实我们之前就见过out了:

        static void Main()
        {
            string str = Console.ReadLine();
            int result;
            bool isSuccess = int.TryParse(str, out result);
            Console.WriteLine("{0},{1}",isSuccess,result);
        }
//输出类型对于引用类型
namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            string name = "Tim";
            int age = -20;
            Student stu;
            bool isSuccess = StudentFactory.CreateStudent(name, age,out stu);
            if (isSuccess)
            {
                Console.WriteLine("{0},{1}",stu.Name,stu.Age);
            }
            else
            {
                Console.WriteLine("The age has error!");
            }
        }
    }
    class Student
    {
        private int age;
        public int Age
        {
            get { return age; }
            set { age = value; }
        }
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }
    class StudentFactory
    {
        public static bool CreateStudent(string name,int age,out Student result)
        {
            result = null;//设置返回初值,放在这个位置牛逼啊
            if (string.IsNullOrEmpty(name))
            {
                return false;
            }
            if (age<0||age>30)
            {
                return false;
            }
            //符合规范:今早return。
            Student stu = new Student() { Age = age, Name = name };
            result = stu;
            return true;
        }
    }
}

四、数组参数

params修饰符

必须是形参列表的最后一个

    class Program
    {
        static void Main()
        {
            int[] array = new int[] { 1, 2, 3 };
            int result = Add(array);
            Console.WriteLine(result);
        }
        static int Add(int[] array)
        {
            int sum = 0;
            foreach (var item in array)
            {
                sum += item;
            }
            return sum;
        }
    }
    class Program
    {
        static void Main()
        {
            int result = Add(1,2,3);
            Console.WriteLine(result);
        }
        static int Add(params int[] array)
        {
            int sum = 0;
            foreach (var item in array)
            {
                sum += item;
            }
            return sum;
        }
    }

其实我们一直看惯的Console.WriteLine也是如此:

还有一个例子,就是split方法:

        static void Main()
        {
            string str = "Tim,Tom;HH?aa";
            string[] strs = str.Split(',', ';', '?');
            foreach (var item in strs)
            {
                Console.WriteLine(item);
            }
        }

五、具名参数

参数位置不受约束。

    class Program
    {
        static void Main()
        {
            int m = 10, n = 20;
            Program.haha(x: n, y: m);
        }

        static void haha(int x,int y)
        {
            Console.WriteLine("{0},{1}",x,y);
        }
    }
//甚至可以如此地整活
        static void Main()
        {
            int x = 10, y = 20;
            Program.haha(x: y, y: x);
        }

六、可选参数

参数因具有默认值而变得可选。

不推荐使用哦。。。

    class Program
    {
        static void Main()
        {
            Program.haha();
        }

        static void haha(int x=100,int y=20)
        {
            Console.WriteLine("{0},{1}",x,y);
        }
    }

七、扩展方法(this参数)

是想对一个类进行扩展,使得该类具有别的类的方法。

比如说:

//对x进行取四位小数
        static void Main()
        {
            double x = 3.112323435;
            x = Math.Round(x, 4);
            Console.WriteLine(x);
        }

感觉这样用下来有点曲折。我们想直接x = x.Round(x,4)看着会简洁明了一些。这时候我们便需要对double这个类进行方法扩展。

namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            double x = Math.PI;
            x = x.Round(4);
            Console.WriteLine(x);
        }
    }
    static class DoubleExtension
    {
        public static double Round(this double x,int y)
        {
            return Math.Round(x, y);
        }
    }
}

对于扩展方法定义的几个注意事项:

1.必须有static修饰的XXXExtension类来收纳对XXX的扩展方法。

2.方法必须是public且static的,但用的时候以实例对象引用

3.必须有this修饰符,且this参数一定要放在第一个。

举例:LINQ方法:

//检测是否全部大于10
        static void Main()
        {
            List<int> list = new List<int>() { 100,111,234,452,324};
            bool result = list.All(i => i > 10);
            Console.WriteLine(result);
        }

//相当于调用如下方法:
        static bool AllGreaterThanTen(List<int> intList)
        {
            foreach (var item in intList)
            {
                if (item <= 10)
                {
                    return false;
                }
            }
            return true;
        }
    

·小技巧:

CTRL+。:自动替换变量名

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值