Как я могу создать список <T>, содержащий открытый универсальный интерфейс? - PullRequest
2 голосов
/ 23 декабря 2010

У меня есть список, который должен содержать IInteract объектов. Но IInteract является универсальным интерфейсом, который требует 2 аргументов типа.

Моя основная идея - перебирать список объектов и «взаимодействовать» друг с другом, если они еще не взаимодействовали. Итак, у меня есть этот объект

List<IObject> WorldObjects = new List<IObject>();

и этот:

private List<IInteract> = new List<IInteract>();

За исключением того, что я не могу скомпилировать последнюю строку, потому что IInteract требует 2 аргумента типа. Но я не знаю, каковы аргументы, пока я не добавлю их. Я мог бы добавить взаимодействия между объектами типа A и A ... или объектами типа B и C.

Я хочу создать классы "Взаимодействие", которые что-то делают с "действующим" объектом и "целевым" объектом, но я хочу, чтобы они были независимы от объектов ... поэтому я мог бы добавить взаимодействие между ними, например. .. "SuperUltraClass" и ... "целое число" .

Я использую неправильный подход?

Ответы [ 6 ]

3 голосов
/ 23 декабря 2010

Предполагается, что IInteract определяется как что-то вроде

interface IInteract<T1, T2>

, и вы используете его для поля класса Foo:

class Foo
{
  List<IInteract...> field;
}

Тогда, если вы хотите отложить решениекакие типы необходимо связать с аргументами типа IInteract, которые вам нужны для параметризации класса контейнера:

class Foo<T1, T2>
{
   List<IInteract<T1, T2>> field;
}

Аргументы типа для IInteract будут связаны при определении конкретного экземпляра класса контейнера, например: var x = new Foo<int, double>(). Это приведет к тому, что поле IInteract будет иметь тип IInteract<int, double> для этого конкретного экземпляра универсального типа Foo.

2 голосов
/ 23 декабря 2010

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

public interface IInteract
{
    void Interact();
}

public interface IInteract<TActor,TTarget> : IInteract
{
    TActor Actor { get; set; }
    TTarget Target { get; set; }
}

Затем вы можете создать свой список IInteract объектов, и он может содержать любые строго типизированные объекты IInteract<TActor,TTarget>, хотя будут доступны только те методы, которые не связаны с универсальным интерфейсом. Важной вещью будут конкретные реализации - именно это определит, какой код будет выполнен в любом случае.

1 голос
/ 23 декабря 2010

Я думаю, вы должны использовать инверсию контейнера управления (в прошлом я использовал Castle Windsor ) Тогда вы можете сделать что-то вроде этого:

void Interact<TA, TB>(TA objectA, TB objectB)
{
    var interact = Container.Resolve<IInteract<TA, TB>>();
    interact.Interact(objectA, objectB);
}
0 голосов
/ 23 декабря 2010

Возможно, вам лучше использовать словарь, где ключ - это кортеж двух типов, с которыми вы взаимодействуете, и значения - Interact, поэтому каждая реализация Interact должна выполнить какое-то приведение

private Dictionary<Tuple<Type, Type>, IInteract<Object, Object>> interactions = new Dictionary<Tuple<Type, Type>, IInteract<Object, Object>>();

Это немного грязно, но потом вы можете добавить к этому:

IInteract<Object, Object> superClassIntInteraction = someInteractionClass;
interactions.Add(new Tuple<Type, Type>(typeof(SuperClass),typeof(int)), superClassIntInteraction);

Я предполагаю, что вы хотите иметь возможность поиска по списку / словарю, чтобы впоследствии найти конкретное взаимодействие, в котором словарь пригодится

0 голосов
/ 23 декабря 2010

вы можете сделать это:

private List<IInteract<SomeType, SomeOtherType>> = new List<IInteract<SomeType, SomeOtherType>>();

Но, как вы сказали, вы не знаете, какие типы вы добавляете. Итак, вот несколько вариантов:

1: используйте object (или даже dynamic) типы:

private List<IInteract<object, object>> ...

2: Используйте дженерики в своем классе:

class Foo<T1, T2> {
    private List<IInteract<T1, T2>> ...
}

...

Foo<string, int> bar = new Foo<string, int>();

Во втором примере вы заблокированы для добавления в список только строк и целых чисел (или того, кем вы создаете объект Foo). В первом примере вы можете смешивать и сопоставлять, но вам нужно будет выполнить проверку типов во время выполнения, чтобы выяснить, что вы вытаскиваете из списка.

0 голосов
/ 23 декабря 2010

Я не уверен, что полностью понимаю, чего вы пытаетесь достичь.Что вам нужно сделать, это создать конкретный класс, который реализует ваш интерфейс, а затем использовать его в вашем списке <>.Вот так:

public interface IInteract
{
   Type A { get; set; }
   Type B { get; set; }
}


public class Interact : IInteract
{
    public Type A
    {
        get { return a; }
    }

    public Type B
    {
        get { return b; }
    }

}

А затем используйте ваш конкретный класс в вашем списке:

private List<Interact> = new List<Interact>();  
...