Массив структур, наследующих интерфейс, выглядит как ссылочный тип - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть структура с именами Foo и Bar - обе, если они реализуют интерфейс с именем IFoo.

public interface IFoo
{
    string StrTest { get; set; }
    int NumTest { get; set; }
}

public struct Foo : IFoo
{
    public Foo(string backTest, int numTest)
    {
        StrTest = backTest;
        NumTest = numTest;
    }

    public string StrTest { get; set; }
    public int NumTest { get; set; }
}

public struct Bar : IFoo
{
    public Bar(string backTest, int numTest)
    {
        StrTest = backTest;
        NumTest = numTest;
    }

    public string StrTest { get; set; }
    public int NumTest { get; set; }
}

Допустим, у меня есть массив IFoo с индексом "0 "У меня есть Foo структура.Проблема возникает, когда я перемещаю эту структуру в новый индекс, такой как «1» (который должен скопировать его).Теперь вы ожидаете, что оба они будут разделены, то есть вы меняете одно и другое не должно также меняться .

Однако я считаю, что еслиЯ изменяю одно из свойств для вновь перемещенного - меняются оба ... разве это не class (тип ссылки) функциональность?

Взгляните на следующий пример:

// Create a list of "BackInterface"s - with foo and bar.
List<IFoo> arr = new List<IFoo>
{
    new Foo("A", 2),
    new Bar("B", 4)
};

// Now, place the SAME struct at index "0" (the foo) at the end - it should be copied?
arr.Add(arr[0]);

// Modify the item at the last newly-created index
arr[2].StrTest = "C";

И arr[0], и arr[2] * StrTest теперь "C".

Если у меня массив всего Foo или Bar, у меня нет этой проблемы -только когда у меня есть массив IFoo.Я также пробовал обычные массивы (типа "object) и ArrayList (у которых нет универсальных шаблонов) - ни один из них не работал.

Есть идеи, что здесь происходит, и как по-прежнему иметь возможность иметь массив как Foo, так и Bar, оба должны иметь реализацию чего-либо?

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Вы не можете иметь массив как Foo, так и Bar, обе структуры, без видимого бокса.

Вы получаете бокс, если вы приводите структуру к интерфейсу, что происходит, когда вы создаете List , а затем помещаете в него свою структуру.Вы можете увидеть, что ваши структуры стали ссылочными типами, выполнив

bool test = arr[0].GetType().IsValueType; 

после создания arr: для List это будет false и для List .

true.некоторые обходные пути, такие как наличие двух массивов: один для Foo и один для Bar, а затем еще один массив для индексации в них обоих.Но это ужасно.См. этот более ранний ответ о переполнении стека для получения дополнительной информации.

Из-за всего этого вообще не очень хорошая идея размещать интерфейсы на структурах: структуры предназначены для облегчения работы в стеке.,Если вам нужно такое поведение, вам лучше использовать классы.

0 голосов
/ 21 декабря 2018

Сохраняя типы значений в переменной, которая имеет тип интерфейса, она упаковывается.Интерфейсы всегда являются ссылочными типами, поэтому неявное преобразование типа значения, реализующего его, к типу интерфейса должно его заполнить.Тип значения в штучной упаковке является ссылочным типом, поэтому вы наблюдаете поведение ссылочного типа, потому что arr[0] на самом деле является ссылочным типом .

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