Передача Func <T, TResult>, где TResult неизвестен - PullRequest
1 голос
/ 16 ноября 2010

Примечание: пожалуйста, пометите и / или переименуйте соответствующим образом


У меня есть класс FooEnumerator, который упаковывает Foo и реализует IEnumerable<FooEnumerator>.Foo s представляют древовидную структуру данных, перечисленные FooEnumerator являются дочерними узлами текущего узла.

Foo - предоставленный поставщиком объект данных.FooEnumerator реализует связку пользовательского кода фильтрации.

class FooEnumerator : IEnumerable<FooEnumerator>
{
    public Foo WrappedNode { get; private set; }
    public string Name { get { return WrappedNode.Name; } }
    public int Id { get{ return WrappedNode.Id; } }
    public DateTime Created { get{ return WrappedNode.Created; } }

    public FooEnumerator(Foo wrappedNode)
    {
        WrappedNode = wrappedNode;
    }

    public IEnumerator<FooEnumerator> GetEnumerator()
    {
          foreach (Foo child in this.GetChildren())
              if(FilteringLogicInHere(child))
                    yield return new FooEnumerator(child);
    }

    ...
}

Я хочу иметь возможность сортировать каждый уровень дерева по заданному (произвольному) выражению, определенному при создании верхнего уровня FooEnumeratorи передать это выражение каждому вновь перечисленному элементу для использования.

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

. Подпись для OrderBy:

OrderBy<TSource, TKey>(Func<TSource, TKey> keySelector)

, где TKey - это тип возвращаемого значения Func, но является параметром типа в сигнатуре метода и вычисляется во время компиляции.

Пример использования

var x = GetStartingNode();

var sort = n => n.DateTime;
var enu = new FooEnumerator(x, sort);

var sort2 = n => n.Name;
var enu2 = new FooEnumerator(x, sort2);

Затем выражение сортировки будет сохранено в переменной класса и FooEnumeratorбудет работать как:

// pseudo-implementation

private Expression<Func<Foo, TKey>> _sortBy;

public FooEnumerator(Foo wrappedNode, Expression<Func<Foo, TKey>> sortBy)
{
    WrappedNode = wrappedNode;
    _sortBy = sortBy;
}

public IEnumerator<FooEnumerator> GetEnumerator()
{
    foreach (Foo child in this.GetChildren().OrderBy(_sortBy))
        if(FilteringLogicInHere(child))
            yield return new FooEnumerator(child);
}

Как я могу указать тип TKey (неявно или явно) в этом случае использования?

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

Ответы [ 2 ]

4 голосов
/ 16 ноября 2010

Ну, вы не можете создать переменную-делегат члена типа Expression<Func<Foo,TKey>>, так как TKey никогда не указывается.Тем не менее, вы можете создать элемент типа Expression<Func<Foo,IComparable>>, который может быть достаточно для ваших целей.Конечно, вам может понадобиться изменить конструктор FooEnumerator, чтобы он также принимал эту подпись.

РЕДАКТИРОВАТЬ: Другие предлагали параметризовать ваш FooEnumerator, чтобы он принимал TKey,Вы, конечно, можете это сделать, но вы должны знать о возникающих проблемах:

  1. При параметризации перечислителя вы затем запускаете процесс. Любой код, который хочетдля хранения FooEnumerator<T> необходимо заранее знать тип T.Однако вы можете реализовать не универсальный интерфейс IFooEnumerator, чтобы справиться с этим.
  2. Параметризация перечислителя создает проблемы, если вы хотите в будущем поддерживать упорядочение по нескольким полям. C #не поддерживает дженерики с переменным числом параметров типа, что ограничивает создание дженериков, требующих нескольких произвольных типов.С этой проблемой сложнее разобраться, так как неудобно начинать создавать FooEnumerator<T>, FooEnumerator<T1,T2>, FooEnumerator<T1,T2,T3...> и т. Д.
1 голос
/ 16 ноября 2010

Вы также можете параметризовать свой перечислитель:

class FooEnumerator<TKey> {

  // ... All your 'pseudo' code would work here

}

Однако я рекомендую программировать для интерфейса с использованием IComparable.

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