C# ссылка на переменную цикла
можно ли в C# что-то вроде следующего
foreach (ref string var in arr) {
var = "new value";
}
чтобы переменная var рассматривалась как ссылка и назначение var изменило бы элемент массива?
5 ответов
нет такой конструкции для обновление цикл; итератор доступен только для чтения. Например, следующее обеспечивает совершенно допустимый итератор:
public IEnumerable<int> Get1Thru5() {
yield return 1; yield return 2; yield return 3;
yield return 4; yield return 5;
}
как бы его обновить? что это обновление?
Если данные являются массивом / списком / etc, то что-то вроде:
for(int i = 0 ; i < arr.Length ; i++) {
arr[i] = "new value";
}
или другие варианты в зависимости от конкретного контейнера.
обновление; в пуш расширение метод:
public static void UpdateAll<T>(this IList<T> list, Func<T, T> operation) {
for (int i = 0; i < list.Count; i++) {
list[i] = operation(list[i]);
}
}
static void Main() {
string[] arr = { "abc", "def", "ghi" };
arr.UpdateAll(s => "new value");
foreach (string s in arr) Console.WriteLine(s);
}
нет. The foreach
оператор - это просто синтаксический сахар поверх IEnumerable
интерфейс. Этот интерфейс определяет метод для получения en IEnumerator
, который, в свою очередь, есть методы, чтобы сделать только для чтения перечисление:
- Current: object
- MoveNext (): bool
- Reset() : void
foreach(string s in strings)
{
Console.WriteLine(s);
}
- это ярлык компилятор:
IEnumerator e = strings.GetEnumerator();
string s;
while(e.MoveNext())
{
s = e.Current;
Console.WriteLine(s);
}
С IEnumerator.Current-это свойство только для получения, которое вы не можете установить.
// Non-generic IEnumerator shown.
interface IEnumerator
{
bool MoveNext();
object Current { get; }
void Reset();
}
если вы хотите поддерживать обновляемый перечислитель, вам нужно будет создать его самостоятельно , но вы не сможете использовать с ним "foreach", и вам придется реализовать обертки вокруг всех общих классов IEnumerable.
вам придется проанализировать текущую ситуацию и выяснить, как обновить. Если вы используете интерфейс IList вы можете сделать:
for(int i = 0; i < strings.Count; ++i)
{
string s = strings[i];
//do work
s = s.ToUpperInvariant();
strings[i] = s;
}
в случае строки Нет; C# строки неизменяемы (не могут быть измененный.) Если бы вы перечисляли объекты другого, изменяемого типа, вы можете изменить свойства этих объекты.
просто чтобы проиллюстрировать, о чем говорит Джейкоб. Рассмотрим фрагмент кода ниже:
class MyInt
{
public int Val { get; set; }
public MyInt(int val) { this.Val = val; }
}
class Program
{
static void Main(string[] args)
{
MyInt[] array = new MyInt[] { new MyInt(1), new MyInt(2) };
foreach (var obj in array) Console.Write("{0}\t", obj.Val);
foreach (var obj in array)
{
obj = new MyInt(100); // This doesn't compile! the reference is read only
obj.Val *= 10; // This works just fine!
}
foreach (var obj in array) Console.Write("{0}\t", obj.Val);
}
}
действительно, если вы попытаетесь назначить "obj", как указано выше, вы получите ошибку времени компиляции. Но ничто не мешает вам изменять свойства MyInt через ссылку "obj"
в случае строки нет; строки C# неизменяемы (не могут быть изменены). При перечислении объектов другого изменяемого типа можно изменить свойства этих объектов.