简体   繁体   中英

Passing arguments by reference in static class methods

I get the error "A property or indexer may not be passed as an out or ref parameter" My task is to implement buble sort as a static class if I make it non static it works just fine.

public static class BubleSort
    {
        public static void Sort(List<int> arr)
        {
            for (int i = 0; i < arr.Count-1; i++)
            {
                var flag = true;
                for (int j = 0; j < arr.Count-i-1; j++)
                {
                    if (arr[j] > arr[j + 1])
                    {
                        Swap(ref arr[j],ref arr[j + 1]);
                        flag = false;
                    }
                }

                if (flag)
                    break;
            }
        }

        private static void Swap(ref int v1,ref int v2)
        {
            int temp = v1;
            v1 = v2;
            v2 = temp;
        }
    }

You cant do what you are trying to do for exactly the reason the compiler says... However you could just use the reference of the list

private static void Swap(IList<int> list, int i)
{
   int temp = list[i];
   list[i] =  list[i+1];
   list[i+1] = temp;
}

Or a 1 liner using tuple deconstruction

if (arr[j] > arr[j + 1])
{
   (arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);
   flag = false;
}
Indexer access returns temporary value. 'ref' argument must be an assignable variable, field or an array element

You cannot send references from a list because access to specific index element is done through Indexer. see more about indexers

Instead, you can send references from an array int[] using ref, because it's not using indexer, but direct reference.

If you still want to use list, you can use C# feature to swap:

(arr[j],arr[j + 1]) = (arr[j + 1], arr[j]);

instead of Swap method

Your code will become

    public static class BubleSort
    {
        public static void Sort(List<int> arr)
        {
            for (int i = 0; i < arr.Count-1; i++)
            {
                var flag = true;
                for (int j = 0; j < arr.Count-i-1; j++)
                {
                    if (arr[j] > arr[j + 1])
                    {
                        (arr[j],arr[j + 1]) = (arr[j + 1], arr[j]);
                        flag = false;
                    }
                }

                if (flag)
                    break;
            }
        }
    }

There is a feature in the language for returning references. But this is only implemented for arrays, not lists, since lists can be re-allocated. So I would expect your example code to work if you changed arr to an array. See for example this minimal example:

        public void SwapTest()
        {
            var arr = new [] {1, 2};
            Swap( ref arr[0], ref arr[1]);
        }

        public static void Swap(ref int a, ref int b)
        {
            var tmp = a;
            a = b;
            b = tmp;
        }

However, for most practical applications I would suggest using one of the solutions posted by @TheGeneral. ref returns are somewhat unusual, and may not be familiar to all programmers.

In this case arr[j] is considered as a property, since it needs to read a field in the List. Properties are not variables. They're methods, and cannot be passed to ref parameters.

If you want to do it this way, you would need to pass the array property to a temporary variable.

Example:

if (arr[j] > arr[j + 1]){
   int tempJ = arr[j];
   int tempJ2 = arr[j + 1];
   Swap(ref tempJ, ref tempJ2);
   arr[j] = tempJ;
   arr[j + 1] = tempJ2;
   flag = false;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM