• out参数,ref参数,params参数数组


    params参数数组

    params关键字可以为方法指定数目可变的参数。params关键字修饰的参数,可以传入任意数目的同类型参数,甚至可以不传入参数。

    不过params修饰的参数必须是方法的最后一个参数,并且一个方法只能有一个params修饰的参数。

    示例

    public class MyClass
    {
        public static void UseParams(params int[] list)
        {
            for (int i = 0; i < list.Length; i++)
            {
                Console.Write(list[i] + " ");
            }
            Console.WriteLine();
        }
    
        public static void UseParams2(params object[] list)
        {
            for (int i = 0; i < list.Length; i++)
            {
                Console.Write(list[i] + " ");
            }
            Console.WriteLine();
        }
    
        static void Main()
        {
            // You can send a comma-separated list of arguments of the 
            // specified type.
            UseParams(1, 2, 3, 4);
            UseParams2(1, 'a', "test");
    
            // A params parameter accepts zero or more arguments.
            // The following calling statement displays only a blank line.
            UseParams2();
    
            // An array argument can be passed, as long as the array
            // type matches the parameter type of the method being called.
            int[] myIntArray = { 5, 6, 7, 8, 9 };
            UseParams(myIntArray);
    
            object[] myObjArray = { 2, 'b', "test", "again" };
            UseParams2(myObjArray);
    
            // The following call causes a compiler error because the object
            // array cannot be converted into an integer array.
            //UseParams(myObjArray);
    
            // The following call does not cause an error, but the entire 
            // integer array becomes the first element of the params array.
            UseParams2(myIntArray);
        }
    }
    /*
    Output:
        1 2 3 4
        1 a test
    
        5 6 7 8 9
        2 b test again
        System.Int32[]
    */

    该示例中,UseParams方法可以接受任意数目的int类型参数,UseParams2方法可以接受任意数目的object类型参数。

    ref引用参数

    ref关键字使参数通过引用传递(非值传递)。通过引用传递参数的效果是:在方法中对参数的任何改变都会保留。

    说明:引用传递和引用类型是两个概念,不要混淆。值类型和引用类型都可以用ref修饰,当通过引用传递时,不会对值类型装箱。

    若要使用ref参数,方法的定义和调用都必须显式使用ref关键字,如下所示:

    class RefExample {
            static void Method(ref int i) {
                // Rest the mouse pointer over i to verify that it is an int.
                // The following statement would cause a compiler error if i
                // were boxed as an object.
                i = i + 44;
            }
    
            static void Main() {
                int val = 1;
                Method(ref val);
                Console.WriteLine(val);
    
                // Output: 45
            }
        }

    传递给ref形参的实参必须先经过初始化才能使用。这与out形参不同,out形参使用前可以不初始化。

    同一个类中的方法签名,差别不能仅仅是参数修饰分别为ref和out。如果两个方法之间的差别仅在于,一个为ref参数,另一个为out参数,则会发生编译错误。例如,下面的代码会编译出错:

    class CS0663_Example
    {
        // Compiler error CS0663: "Cannot define overloaded 
        // methods that differ only on ref and out".
        public void SampleMethod(out int i) { }
        public void SampleMethod(ref int i) { }
    }

    不过,有ref(out)和没ref(out)的函数可以重载,如下所示,可以通过编译:

    class RefOverloadExample
    {
            public void SampleMethod(int i) { }
            public void SampleMethod(ref int i) { }
    }

    属性不是变量,它们是方法,所以不能作为ref参数传递。

    下面类型的方法不能使用ref和out关键字:

    • 异步方法,即以async修饰符修饰的方法。
    • 迭代器方法,包括yield returnyield break 声明语句。

    out输出参数

    在ref中已经对out有所介绍,下面对out参数进行详细解析。out关键字可以应用在两个地方:参数修饰符;接口或委托中修饰泛型类型参数。首先介绍参数修饰符部分。

    参数修饰

    out关键字通过引用传递参数。这与ref关键字相似,不过ref要求在传递之前初始化而变量,out没有此要求。和ref一样,方法定义和调用处都必须显式使用out关键字。例如:

    class OutExample
    {
        static void Method(out int i)
        {
            i = 44;
        }
        static void Main()
        {
            int value;
            Method(out value);
            // value is now 44
        }
    }

    虽然out参数传递的变量无需在传递之前初始化,但需要在方法返回之前赋值。

    示例

    如果希望方法返回多个值,可以声明out方法。下面的示例使用out返回具有单个方法调用的三个变量。注意,第三个参数赋为null值,这使得方法可以由选择地返回值。

    class OutReturnExample
        {
            static void Method(out int i, out string s1, out string s2)
            {
                i = 44;
                s1 = "I've been returned";
                s2 = null;
            }
            static void Main()
            {
                int value;
                string str1, str2;
                Method(out value, out str1, out str2);
                // value is now 44
                // str1 is now "I've been returned"
                // str2 is (still) null;
            }
        }

    泛型修饰符

    对于泛型类型参数,out关键字可指定该类型参数是协变的。可以在泛型接口和委托中使用out关键字。

    通过协变,可以使用比指定类型派生程度更大的类型。这样可以对委托类型和实现变体接口的类进行隐式转换。引用类型支持协变和逆变,值类型不支持。

    如果接口具有协变类型形参,则允许其返回派生程度更大的实参。例如,.NET framework 4中的IEnumerable<T>接口,其类型T是协变的,因此无需使用任何特殊的转换方法就可以将IEnumerable<Of String>类型的对象分配给IEnumerable<Of Object>类型的对象。

    可以向协变委托分配同一类型的其他委托,但需使用派生程序更大的泛型类型参数。

    示例

    下面演示如何声明、扩展和实现一个协变泛型接口。此外还演示如何对实现协变接口的类使用隐式转换。

    // Covariant interface.
    interface ICovariant<out R> { }
    
    // Extending covariant interface.
    interface IExtCovariant<out R> : ICovariant<R> { }
    
    // Implementing covariant interface.
    class Sample<R> : ICovariant<R> { }
    
    class Program
    {
        static void Test()
        {
            ICovariant<Object> iobj = new Sample<Object>();
            ICovariant<String> istr = new Sample<String>();
    
            // You can assign istr to iobj because
            // the ICovariant interface is covariant.
            iobj = istr;
        }
    }

    在泛型接口中,当符合下列条件,可将类型参数声明为协变的

    • 类型形参仅用作接口方法的返回类型,不用作方法实参的类型。
      说明:此规则有个例外,如果在协变接口中,包含用作方法参数的逆变泛型委托,则可以将协变类型用作此委托类型参数。
    • 类型参数不用作接口方法的泛型约束。

    下面演示如何声明、实例化和调用一个协变泛型委托:

    // Covariant delegate.
    public delegate R DCovariant<out R>();
    
    // Methods that match the delegate signature.
    public static Control SampleControl()
    { return new Control(); }
    
    public static Button SampleButton()
    { return new Button(); }
    
    public void Test()
    {            
        // Instantiate the delegates with the methods.
        DCovariant<Control> dControl = SampleControl;
        DCovariant<Button> dButton = SampleButton;
    
        // You can assign dButton to dControl
        // because the DCovariant delegate is covariant.
        dControl = dButton;
    
        // Invoke the delegate.
        dControl(); 
    }

    在泛型委托中,如果类型仅用作方法返回类型,且不用于方法参数,则可声明为协变的。
  • 相关阅读:
    月薪 30K Java 程序员,需要掌握哪些技术?
    docker-compose安装mongodb
    docker-compose安装apollo服务
    docker-compose安装mysql和redis
    编程总结1:打印沙漏
    秋季学习总结
    对我人生影响最大的三位老师
    自我介绍
    秋季学习总结
    人生路上对我影响最大的三位老师
  • 原文地址:https://www.cnblogs.com/jiawei-whu/p/4342868.html
Copyright © 2020-2023  润新知