开发者

How to create a generic type that takes either T or IEnumerable<T>?

Let's say I have a type:

public class Transformer<T, TResult>
    where T : IMessage
    where TResult : IMessage
{
    private Func<T, IEnumerable<TResult>> _transformer;

    public Transformer(Func<T, TResult> transformer)
    {
        _transformer = null // ?
    }

    public Transformer(Func<T, IEnumerable<TResult>> transformer)
    {
        _transformer = transformer;
    }
}

So in essence, I'd like to convert Func<T, T开发者_运维问答Result> into Func<T, IEnumerable<TResult>> in the first constructor.

I've tried to create a private inner class that takes Func<T, TResult> and defined a method that returns IEnumerable like this:

private class TransformerWrapper
{
    private readonly Func<T, TResult> _func;

    public TransformerWrapper(Func<T, TResult> func)
    {
        _func = func;
    }

    public IEnumerable<TResult> Transform<T>(T message) where T : IMessage
    {
        yield return _func(message);
    }
}

But it's not really working out. I get an error saying delegate has an invalid argument - cannot convert from T to T.

First of all, what is happening with the compiler error and second, is there another way?

Update

Minutes after I posted, I found a solution:

public Transformer(Func<T, TResult> transformer)
{
    _transformer = new TransformerWrapper<T, TResult>(transformer).Transform;
}

And,

private class TransformerWrapper<T, TResult>
{
    private readonly Func<T, TResult> _func;

    public TransformerWrapper(Func<T, TResult> func)
    {
        _func = func;
    }

    public IEnumerable<TResult> Transform(T message)
    {
        yield return _func(message);
    }
}

I still can't get my head around why the first solution did not work. I need to think about that one...


Try this:

public Transformer(Func<T, TResult> transformer)
{
    _transformer = t => Convert(t, transformer);
}

private static IEnumerable<TResult> Convert(T value, Func<T, TResult> transformer)
{
    yield return transformer(t);
}


You're specifying a new generic type T in the Transform<T> function. As T and TResult are already defined in the parent class, there's no need for anything in the child class to be generic.

Remove the <T> and the generic qualifier from the method signature and it should compile.

public IEnumerable<TResult> Transform(T message)
{
    yield return _func(message);
}


Change your inner class to:

    private class TransformerWrapper
    {
        private readonly Func<T, TResult> _func;

        public TransformerWrapper(Func<T, TResult> func)
        {
            _func = func;
        }

        public IEnumerable<TResult> Transform(T message)
        {
            yield return _func(message);
        }
    }
}

Compile already knows what T is, and you don't need to constrain the method again.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜