Интересные функции «params of ref», любые обходные пути?

Интересно, будет ли что-то вроде этого возможно для типов значений …

public static class ExtensionMethods { public static void SetTo(this Boolean source, params Boolean[] bools) { for (int i = 0; i < bools.Length; i++) { bools[i] = source; } } } 

то это было бы возможно:

 Boolean a = true, b, c = true, d = true, e; b.SetTo(a, c, d, e); 

Конечно, это не работает, потому что bools являются типом значений, поэтому они передаются в функцию как значение, а не как ссылка.

Помимо переноса типов значений в ссылочные типы (путем создания другого classа), есть ли способ передать переменную в функцию ссылкой (ref) при использовании модификатора params?

    Это невозможно. Чтобы объяснить, почему, сначала прочитайте мое эссе о том, почему мы оптимизируем освобождение локальных переменных типа значения, помещая их в стек:

    http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

    Теперь, когда вы это понимаете, должно быть понятно, почему вы не можете хранить «ref bool» в массиве. Если бы вы могли, тогда у вас мог бы быть массив, который выживет дольше, чем ссылка на стек. У нас есть два варианта: либо разрешить это, либо создать программы, которые грохочут и умирают ужасно, если вы ошибаетесь – это выбор, сделанный разработчиками C. Или, запретить его, и иметь систему, которая менее гибкая, но более безопасный. Мы выбрали последнее.

    Но давайте подумаем об этом немного глубже. Если вы хотите передать «вещь, которая позволяет мне установить переменную», мы имеем это . Это просто делегат:

     static void DoStuff(this T thing, params Action[] actions) { foreach(var action in actions) action(thing); } ... bool b = whatever; b.DoStuff(x=>{q = x;}, x=>{r = x;} ); 

    Имеют смысл?

    К сожалению, сообщество Java, а теперь и .NET, разработчики решили, что меньшая гибкость во имя «безопасности» является предпочтительным решением, и для достижения того же результата с меньшим количеством строк кода вы должны выбрать необычную сложность (все эти classы структуры, delegates и т. д.).

    В Delphi я мог бы просто сделать что-то вроде этого:

     var a: integer; f: double; n: integer; sscanf(fmtstr, valuestr, [@a, @f, @n]); 

    // <- "sscanf" - это функция, которую я написал сам, которая принимает открытый массив указателей.

    В C # вам нужно будет:

     int a; double f; int n; object [] o = new object[]; sscanf(fmtstr, valuestr, ref o); a = o[0]; f = o[1]; n = o[2]; 

    Это 5 строк кода, чтобы сделать то, что я мог бы сделать в 1 строке кода Delphi. Я думаю, что есть где-то формула, что вероятность ошибок в коде возрастает геометрически с количеством строк кода; поэтому, если у вас есть 20 строк кода, вы получаете код в 4 раза чаще, чем если бы у вас было 10.

    Конечно, вы можете уменьшить # строки кода, используя делегат со всеми этими странными угловыми скобками и странным синтаксисом, но я бы подумал, что это также убежище для ошибок.

    На самом деле нет способа. Вы могли бы сделать что-то вроде этого:

     public static void Main(string[] args) { BooleanWrapper a = true, b = true, c = true, d = true, e = new BooleanWrapper(); b.SetTo(a, c, d, e); } public static void SetTo(this BooleanWrapper sourceWrapper, params BooleanWrapper[] wrappers) { foreach (var w in wrappers) w.Value = sourceWrapper.Value; } public class BooleanWrapper { public BooleanWrapper() { } public BooleanWrapper(Boolean value) { Value = value; } public Boolean Value { get; set; } public static implicit operator BooleanWrapper(Boolean value) { return new BooleanWrapper(value); } } 

    Но опять же, как это лучше, чем просто делать это:

     public static void Main(string[] args) { Boolean[] bools = new Boolean[5]; bools.SetTo(bools[1]); // Note I changed the order of arguments. I think this makes more sense. } public static void SetTo(this Boolean[] bools, Boolean value) { for(int i = 0; i < bools.Length; i++) bools[i] = value; } 

    В конце концов, массив представляет собой последовательность переменных. Если вам нужно что-то, что ведет себя как последовательность переменных, используйте массив.

    Это было бы невозможно, даже если бы bool s были ссылочными типами. Хотя class является ссылочным типом, переменная в Boolean[] по-прежнему является значением , просто это значение является ссылкой . Присвоение значения ссылки просто изменяет значение этой конкретной переменной. Понятие массива переменных ref не имеет смысла (поскольку массивы по своей природе представляют собой ряд значений).