Как бороться с частным участником доступа и коллекциями? - PullRequest
0 голосов
/ 01 февраля 2010

У меня есть классовая иерархия, подобная этой

public class A
{
    protected class B 
    {
        String Name { get; set; }
    }

    protected class C : KeyedCollection<String, B> 
    {
        // ...
    }

    protected C Collection { get; }

    // ...

    public A Copy () 
    {
        // Creates a deep copy of this instance.
    }
}

Теперь я хотел бы написать модульный тест для сравнения, если два экземпляра A имеют одинаковые элементы B внутри свойства KeyedCollection. Однако я не могу выполнить цикл foreach для экземпляров A. То, что я пробовал,

[TestClass]
public class TestClass
{
    public void ATest()
    {
        A original = new A();
        A copy = A.Copy();

        // ...

        A_Accessor originalAccessor = A_Accessor.AttachShadow(original);
        A_Accessor copyAccessor = A_Accessor.AttachShadow(copy);

        foreach(var originalItem in originalAccessor.Collection)
        {
            var copyItem = copyAccessor[originalItem.Name];
            Assert.AreEqual(originalItem, copyItem);
        }
    }
}

Этот код даже не компилируется, потому что средство доступа к классу C не реализует интерфейс IEnumerable (он не реализует интерфейс из класса KeyedCollection). У кого-нибудь есть идеи о том, как мне преодолеть эту проблему?

Я получаю сообщение об ошибке

оператор foreach не может работать с переменными типа «C», поскольку «A_Accessor.C» не содержит открытого определения для «GetEnumerator»

Ответы [ 4 ]

0 голосов
/ 02 февраля 2010

Мне кажется, что вы тестируете детали реализации, а не предполагаемый уровень API для пользователей вашей библиотеки.

0 голосов
/ 01 февраля 2010

Я только что попытался скомпилировать ваш пример: Как и ожидалось, я получил ошибку

Inconsistent accessibility: field type 'A.C' is less accessible than field 'A.Collection'.

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

EDIT

Вы можете использовать originalAccessor.Collection.Target и привести его к ICollection.Конечно, в этом случае вы можете перечислить только object с, поэтому вам придется разыгрывать каждый предмет снова:

foreach (var item in (originalAccessor.Collection.Target as ICollection)) {
   A_Accessor.B casted = A_Accessor.B.AttachShadow(item);
   var copyItem = copyAccessor[casted.Name];
   Assert.AreEqual(casted, copyItem);
}
0 голосов
/ 01 февраля 2010

На самом деле решение, которое я нашел, было очень похоже на предложение Мартина:

var originalItems = 
    from item in (originalAccessor.Collection.Target as IEnumerable).Cast<Object>()
    select A_Accessor.B.AttachShadow(item);

var copyItems = 
    from item in (copyAccessor.Collection.Target as IEnumerable).Cast<Object>()
    select A_Accessor.B.AttachShadow(item); 

foreach(var original in originalItems) 
{ 
    String originalName = original.Name;
    A_Accessor.B copy = copyItems.First(b => b.Name == originalName);

    // ...
}

Спасибо за вашу помощь! Карлос.

0 голосов
/ 01 февраля 2010

Непонятно, как вам удается представить закрытый тип класса через защищенное свойство для начала, но, поскольку C наследуется от KeyedCollection, он уже должен наследовать реализацию IEnumerable<B>.

Не совсем понятно, что вы пытаетесь сделать, но вы все равно должны иметь возможность перебирать коллекцию ... если вы даже можете видеть свойство. Я подозреваю, что ваш код не компилируется по другим причинам - потому что C объявлен в терминах закрытого типа члена, несмотря на его защиту, и потому что вы пытаетесь получить доступ к C из другого класса в первую очередь ( несмотря на то, что он защищен).

...