Почему редактируемое значение свойства сохраняется? - PullRequest
0 голосов
/ 17 июня 2019

Читая вопрос о concurrency в коллекции, сделанной другим пользователем, я начал пытаться написать свою собственную threadsafe list class.

После этого я создал тестовый сценарий, который я пытался использовать, и в результате он выдавал ошибки на foreach из-за оригинального GetEnumerator метода, который был:

public IEnumerator<T> GetEnumerator()
{
    lock (Lock)
    {
        return List.GetEnumerator();
    }
}

Я написал это снова (прочитав несколько советов в Интернете), таким образом, и это сработало. Я думал, что это просто возвращение копии original collection's enumerator:

public IEnumerator<T> GetEnumerator()
{
    lock (Lock)
    {
        using (IEnumerator<T> enumeratorCopy = List.GetEnumerator())
        {
            while (enumeratorCopy.MoveNext())
            {
                yield return enumeratorCopy.Current;
            }
        }
    }
}

Затем для любопытства я попытался отредактировать свойство данного class и заметил, что отредактированные значения сохраняются.

Можете ли вы объяснить мне, почему? yield дает reference вместо value?

Это полный код:

class Program
{
    private static ThreadSafeList<Dog> Dogs = new ThreadSafeList<Dog>();
    static void Main(string[] args)
    {
        Task.Run(() =>
        {
            while (true)
            {
                Dogs.Add(new Dog(Guid.NewGuid().ToString()));
                Thread.Sleep(500);
            }
        });

        while (true)
        {
            Print("{0} - There are {1} Dogs registered.", DateTime.Now, Dogs.Count);
            foreach (Dog dog in Dogs)
            {
                Print("{0} - {1}", DateTime.Now, dog);
                dog.EditCreationDateTime(default(DateTime));
            }
            Thread.Sleep(100);
        }
    }
    private static void Print(string message, params object[] args)
    {
        Console.WriteLine(string.Format(message, args));
    }
}

public class Dog
{
    public Guid Guid { get; private set; }
    public string Name { get; private set; }
    public DateTime CreationDateTime { get; private set; }

    public Dog(string name)
    {
        Guid = Guid.NewGuid();
        Name = name;
        CreationDateTime = DateTime.Now;
    }

    public override string ToString()
    {
        return string.Format("{{ Guid: {0}, Name: {1}, CreationDateTime: {2} }}", Guid, Name, CreationDateTime);
    }

    public void EditCreationDateTime(DateTime dateTime)
    {
        CreationDateTime = dateTime;
    }
}

public class ThreadSafeList<T> : IEnumerable<T>, IEnumerable
{
    private List<T> List { get; set; }
    private object Lock { get; set; }

    public int Count
    {
        get
        {
            lock (Lock)
            {
                return List.Count;
            }
        }
    }

    public ThreadSafeList()
    {
        List = new List<T>();
        Lock = new object();
    }

    public T this[int index]
    {
        get
        {
            lock (Lock)
            {
                return List[index];
            }
        }

        set
        {
            lock (Lock)
            {
                List[index] = value;
            }
        }
    }

    public void Add(T obj)
    {
        lock (Lock)
        {
            List.Add(obj);
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        lock (Lock)
        {
            using (IEnumerator<T> enumeratorCopy = List.GetEnumerator())
            {
                while (enumeratorCopy.MoveNext())
                {
                    yield return enumeratorCopy.Current;
                }
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        lock (Lock)
        {
            using (IEnumerator<T> enumeratorCopy = List.GetEnumerator())
            {
                while (enumeratorCopy.MoveNext())
                {
                    yield return enumeratorCopy.Current;
                }
            }
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Значение CreationDateTime изменить.

"Print бесконечный цикл" печатать в первый раз перед изменением значения.

При выходе из цикла начинается новый цикл вВ то же время Task добавил новые элементы в список собак.

"Print бесконечный цикл" перезапустите цикл, перепечатайте элемент с измененным значением в CreationDateTime и напечатайте новых собак, добавленных после первогоцикл.

И так далее ...

0 голосов
/ 17 июня 2019

Dog равен class, что делает его ссылочным типом

В C # есть два типа типов: ссылочные типы и типы значений.Переменные ссылочных типов хранят ссылки на свои данные (объекты), в то время как переменные типов значений напрямую содержат их данные.В ссылочных типах две переменные могут ссылаться на один и тот же объект;следовательно, операции с одной переменной могут повлиять на объект, на который ссылается другая переменная.В случае типов значений каждая переменная имеет свою собственную копию данных, и операции с одной переменной не могут влиять на другую (кроме случаев, когда переменные параметров in, ref и out; см. Модификатор параметров in, ref и out).).

Объекты yield ed ссылаются на те же самые объекты в частном свойстве List.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...