A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 黑马郭 于 2013-12-27 22:09 编辑

就是自定义一个方法 什么时候需要返回值 ,什么时候不需要;什么时候需要参数 ,什么时候不需要参数。
自己练习写代码的时候也写过,就是思路上卡住了,有点想不通,请大家指点一下。谢谢……

评分

参与人数 1技术分 +1 收起 理由
V_John + 1

查看全部评分

11 个回复

倒序浏览
我也不才,就说下个人意见。
首先,方法是什么,是若干语句的组合,用以完成特定的功能,可以有参数、返回值。
这样,决定是否需要参数、返回值就落到了特定的功能上了。安装功能的需要从而决定是否需要他们。
一般是这样的,如果完成该特定的功能需要方法外的数据支持,则需要设置参数;如果该特定功能会对方法外的成员有用时,则可以设置返回值,如该特定的功能是产生一个结果(不妨假定是数组),则可以设置返回值将该数值结构返回。
总之,明确方法的功能。

评分

参与人数 1技术分 +1 收起 理由
V_John + 1 大家很细心啊

查看全部评分

回复 使用道具 举报
你方法要实现什么功能?那个功能需要这个方法提供什么 那就是返回值  不需要提供就void  比如方法里面写Console.WriteLine("xxxx");那么这个方法就不需要返回值  因为他执行了一个输出参数,当然你也可以让他有返回值  比如如果输出成功就返回1  不成功就返回0     都是看需要的,至于参数   方法就是经常调用的东西  所以把不变的写成方法   变化的让他作为参数传递进来

评分

参与人数 1技术分 +1 收起 理由
V_John + 1 大家很细心啊

查看全部评分

回复 使用道具 举报
先调用方法:
需要返回值的时候,就返回值,不需要就不返回,也不需要定义返回值类型。方法需要参数的时候你就传参,不需要就不传。
别纠结太多,知识是慢慢积累的。PS:我也是菜鸟
回复 使用道具 举报
什么是方法?

你需要他做什么 这个就是方法

举例子

你给钱给你老婆买米,你要拿米做饭
要你老婆买米这就是方法
买米得要钱 你要给你老婆钱 那么这个就是参数 你要把钱传给给老婆买米这个方法
那么 你老婆买完米 给你去做饭  那么 米这个就是返回值

如果你老婆本身有钱,并且你不需要米 那么你就不需要参数也不需要返回值


我觉得我真是天才!

评分

参与人数 1技术分 +1 收起 理由
V_John + 1 大家很细心啊

查看全部评分

回复 使用道具 举报 1 0
这个主要看你方法的完成功能:
为什么要使用方法:个人认为是面向对象编程之后出现的,以前的编程基于计算机逻辑思维编程(对于流程编程),任何代码都要一步一步的完善,还必须写在主方法中。比如主方法上半部分和下半部分代码一样,我们必须还要重新再写一遍,如果我把相同的代码写在一个方法中,我在这里只需要调用两次就搞定了。不带是主方法看的清晰,而且还使代码实现了重用,减少了大量的工作。
这也是用方法的目的之一:实现代码重用,想完成特定的功能
什么时候使用参数:参数是一个桥梁,用来连接不同方法,并且向对应的方法中传递信息。
什么时候使用返回值:返回值也就是实现传递信息的作用,参数是向方法内传入信息,返回值则是向方法外传递信息。
对于方法中使用ref,out ,params关键字,可以另行看看。
个人见解,不足之处请指教。

评分

参与人数 1技术分 +1 收起 理由
V_John + 1 大家很细心啊

查看全部评分

回复 使用道具 举报
菜刀砍电线 发表于 2013-12-26 21:25
先调用方法:
需要返回值的时候,就返回值,不需要就不返回,也不需要定义返回值类型。方法需要参数的时候 ...

一起学习呀
回复 使用道具 举报
红鹰(Jake) 发表于 2013-12-27 09:45
这个主要看你方法的完成功能:
为什么要使用方法:个人认为是面向对象编程之后出现的,以前的编程基于计算 ...

学习了……
回复 使用道具 举报
Sayme 发表于 2013-12-26 22:52
什么是方法?

你需要他做什么 这个就是方法

你回答的真有才……
回复 使用道具 举报
曹华 发表于 2013-12-26 18:41
我也不才,就说下个人意见。
首先,方法是什么,是若干语句的组合,用以完成特定的功能,可以有参数、返回 ...

谢谢回答……
回复 使用道具 举报
C#方法

C#方法

1:实例构造器和类

2:实例构造器和结构

3:类型构造器

4:操作符重载方法

5:转换操作符方法

6:扩展方法

7:部分方法



这篇博客的内容基本上是CLR via C#中第八章 “方法”的大致内容,如果我说得不对,欢迎大家搬砖头



1:实例构造器和类

构造器是允许将类型的实例初始化为良好状态的一种特殊方法,创建一个引用类型的实例时,先为实例的数据字段分配内存,然后初始化对象的附加字段(类型对象指针和同步索引),最后调用构造函数来设置对象的初始状态。构造函数不能被继承,所以不能被virtual、new、override、sealed和abstract修饰,若没有显示定义任何构造函数,编译器将定义一个无参的public构造函数,但若是抽象类,编译器将定义一个无参的protected的构造函数



创建一个类的实例并不一定非要调用构造函数。

1:使用Object的MemberwiseClone()方法。他的作用就是创建当前 System.Object 的浅表副本,内部工作机制是分配内存,初始化对象的附加字段(类型对象指针和同步索引),然后将源对象的字节数据复制到新对象中。从下面的代码可以看出MemberwiseClone()实现了对象复制,而不是简单的对象引用。

复制代码
    class Program
    {
        public int X;
        static void Main(string[] args)
        {
            Program p = new Program();
            p.X = 1;
            Program q = (Program)p.MemberwiseClone();
            Program z = p;
            p.X = 2;
            Console.WriteLine("p.X=" + p.X);//输出:p.X=2
            Console.WriteLine("q.X=" + q.X);//输出:q.X=1
            Console.WriteLine("z.X=" + z.X);//输出:z.X=2
            Console.Read();
        }
    }
复制代码
2:反序列化。在网络编程的时候,经常将一个对象序列化成二进制,然后传输出去,接收端反序列化成原来的对象,反序列化使用的是类

System.Runtime.Serialization.FormatterServices的方法public static object GetUninitializedObject(Type type)或

public static object GetSafeUninitializedObject(Type type)分配内存,而在这两个方法内部没有调用要被反序列化对象的构造函数。

字段的初始化代码会被编译器自动添加到相应的构造函数中,非静态字段的初始化代码会自动加到实例构造函数中,静态字段的初始化代码则添加到静态构造函数中,如果你的代码中有多个字段被初始化,还有多个构造函数的话,初始化代码在每个构造函数中都会有一份,这无疑会让你的生成文件(如DLL,EXE文件)变大。

证明这一点的代码如下:

复制代码
   public class SomeType
    {
        public  int x=1,y=2,z=3;
        public SomeType() { }
        public SomeType(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public SomeType(int x)
        {
            this.x = x;
        }
}
//经过IL反编译,方法SomeType(int x, int y)代码如下
.method public hidebysig specialname rtspecialname
        instance void  .ctor(int32 x,
                             int32 y) cil managed
{
  // 代码大小       45 (0x2d)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.1
  IL_0002:  stfld      int32 MyTest.SomeType::x
  IL_0007:  ldarg.0
  IL_0008:  ldc.i4.2
  IL_0009:  stfld      int32 MyTest.SomeType::y
  IL_000e:  ldarg.0
  IL_000f:  ldc.i4.3
  IL_0010:  stfld      int32 MyTest.SomeType::z
  IL_0015:  ldarg.0
  IL_0016:  call       instance void [mscorlib]System.Object::.ctor()
  IL_001b:  nop
  IL_001c:  nop
  IL_001d:  ldarg.0
  IL_001e:  ldarg.1
  IL_001f:  stfld      int32 MyTest.SomeType::x
  IL_0024:  ldarg.0
  IL_0025:  ldarg.2
  IL_0026:  stfld      int32 MyTest.SomeType::y
  IL_002b:  nop
  IL_002c:  ret
} // end of method SomeType::.ctor
复制代码
先执行了初始化代码,其他构造函数都包含了初始化代码,然后在执行构造函数中的赋值代码,要解决这个代码膨胀问题,方法很简单,把初始化代码写在无参构造函数中,让其他构造函数调用。



2:实例构造器和结构

值类型的工作方式与引用类型截然不同,值类型其实并不需要定义构造函数,地球人根本阻止不了值类型实例化,编译器根本不会生产默认无参构造函数,如果你显示声明无参构造函数,编译根本通过不了,报错“结构不能包含显式的无参数构造函数”。由于值类型存在栈中,根本不需要对堆中的数据进行引用,所以我们可以在定义的时候就直接赋值,(int i=0;string s=”a”;Point p;p.X=2;)他根本不需要new,new当然是可以的,调用构造函数会初始化所有的字段成相应类型的默认值,实例如下:

复制代码
   public struct Point
    {
        public int x, y;
        //public Point() { }//错:结构不能包含显式的无参数构造函数
        //public int z = 4;//错:结构中不能有实例字段初始值设定项
        //public Point(int x) //在控制返回调用方之前,字段“Point.y”必须被完全赋值,要解决这个问题就手动给y加一个默认值吧,
        //你也可以加this=new Point();将所有的字段的值初始化为0或null
        //{
        //    this.x = x;
        //}
        public void Test()
        {
            Point p;
            p.x = 1;
            p.y = 2;
            Console.WriteLine(p.x+","+p.y);//输出1,2
        }
    }
复制代码
结构的特点:

   1:不能显示定义无参构造函数

   2:不能在定义字段的时候初始化

   3:声明有参构造函数的时候,要初始化所有的字段



3:类型构造器

实例构造器就是静态构造函数,他的作用是设置类型的初始化状态,静态构造函数只能有一个,且是无参的,不能有访问修饰符修饰,默认就是private,由编译器调用执行。实例如下:

复制代码
public class SomeType
    {
        public static int x = 520;
        static SomeType()
        {
            x = 112;
        }
    }
   
    //用.NET reflector查看源码,如下
    public class SomeType
    {
        public static int x ;
        static SomeType()
        {
            x = 520;
            x = 0x70;
        }
        public SomeType() { }
    }
复制代码
在定义静态字段并初始化,编译器会自动生成一个类型构造器(静态构造函数),并将静态字段的初始化代码插在类型构造器的前面,从上面的代码可以看出,定义时初始化和在类型构造器中初始化只需要一个即可,还有112的16进制为0x70,所以在代码中看到16进制也不用大惊小怪,根本不涉及性能问题,若定义了静态字段,但没有初始化任何一个,编译器是不会生成类型构造器的。但是静态字段还是会被初始化,其实不管是静态的还是非静态的字段都是会被编译器自动初始化的,int类型的初始化为0;bool:False;string:null,这就是为什么你在实例化实体的时候,有些字段你没有初始化,却不会报错,而且你知道没有初始化的字符串的值就是null,也就是说编译器会帮你初始化你没有初始化的字段,然而在方法中定义的局部变量是需要自己初始化的,如果你没有初始化,会报一个错误“使用了未赋值的局部变量X”。



4:操作符重载方法

要想实现操作符重载,只需要保证以下两点,其他的话都是浮云:

1:操作符重载方法必须是public和static方法

2:操作符重载方法至少有一个参数的类型与当前定义这个方法的类型相同。之所以是要这个条件是为了使编译器在合理的时间内找到要绑定的操作方法,实例如下



复制代码
public class Complex
    {
        public int data;
        public Complex(int data)
        {
            this.data = data;
        }
        public static Complex operator +(Complex c1, Complex c2)
        {
            return new Complex(c1.data+c2.data);
        }

        public void Test()
        {
            Complex c1 = new Complex(1);
            Complex c2 = new Complex(2);
            Complex c3 = c1 + c2;
            Console.WriteLine(c3.data);//输出3
        }
    }
复制代码


回复 使用道具 举报
5:转换操作符方法

要实现转换操作符方法,条件和操作符重载方法的条件是一样的,实例如下:

复制代码
public class Rational
    {
        public Rational(int data)
        {
            this.data = data;
        }

        public Rational(char data)
        {
            this.data = (int)data;
        }

        //隐式类型转换:int->Rational
        public static implicit operator Rational(int data)
        {
            return new Rational(data);
        }

        //隐式类型转换:char->Rational
        public static implicit operator Rational(char data)
        {
            return new Rational(data);
        }

        //显示类型转换 Rational->int
        public static explicit operator int(Rational val)
        {
            return val.data;
        }

        //显示类型转换 Rational->char
        public static explicit operator char(Rational val)
        {
            return Convert.ToChar(val.data);
        }

        public void Test()
        {
            Rational r1 = 1;//将int类型隐式转换成Rational
            Rational r2 = '2';//将char类型隐式转换成Rational
            int i = (int)r1;//将Rational类型显示转换成int
            char c = (char)r2;//将Rational类型显示转换成char
            Console.WriteLine("i=" + i);//输出:i=1
            Console.WriteLine("c=" + c);//输出:c=2
        }
         
        int data;
    }
复制代码
隐式和显示类型转换的实现原理就这么简单,在C++中隐式类型转换根本不需要你写代码,只要有相应的public构造函数就可以了,如int转换成Rational,只需要有构造函数public Rational(int data)就可以了,如Rational r=1;编译器会尽一切努力寻找将int类型转换成Rational的方法,当它发现这个构造函数,他说都不说就帮你进行转换了,就因为这样有时候非常坑爹,你一个int类型无缘无故的就变成Rational了,而你却根本不知道怎么回事,有时候为了解决这个问题,还得自己定义一个类(Uint)来封装int,然后构造函数改成Rational(Uint data),C#就没有这个问题,当然你要想实现隐式类型转换就自己写代码吧。



6:扩展方法

实现扩展方法的条件:

1:定义扩展方法的类必须是非泛型静态类

2:这个类必须有自己的作用域,即不能是内部类

3:方法必须是public和static

4:方法的第一个参数必须用this修饰,第一个参数就是你要扩展的类型,实例如下:

复制代码
public static class StringExtensions
    {
        public static int ToInt(this string s)
        {
            return Convert.ToInt32(s);
        }

        public void Test()
        {
            string s = "2";
            Console.WriteLine(s.ToInt());
        }
}

评分

参与人数 1技术分 +1 收起 理由
V_John + 1 好强大

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马