2

我有一个接受T并有一个方法的类,该方法接受HttpResponseMessage并修改响应中的内容。

public class MyClass<T> {

    HttpResponseMessage Modify(HttpResponseMessage response) {
        T content;
        if(response.TryGetContentValue(out content)) {
            DoSomethingWithContent(content);
        }
        return response;
    }

    public void DoSomethingWithContent(T content) {}

    public void DoSomethingWithContent(IEnumerable<T> content) {}
}

像这样使用...

只要响应内容值是 type T, 它就可以工作,但有时它是IEnumerable<T>,在这种情况下TryGetContentValue()会返回 false ,因为Tis notIEnumerable<T>。所以我创建了一个重载,DoSomethingWithContent但我正在努力找出一种有效的方法来动态转换或声明content为正确的类型,以便调用正确的重载。

回答

我选择了recursive答案,但我想发布完整的方法以供参考:

public class MyClass<T> {

    HttpResponseMessage Modify(HttpResponseMessage response) {
        object content;
        if(response.TryGetContentValue(out content)) {
            if(content is IEnumerable<T>)
                DoSomethingWithContent((IEnumerable<T>)content);
            else
                DoSomethingWithContent((T)content);
        }
        return response;
    }

    public void DoSomethingWithContent(T content) {}

    public void DoSomethingWithContent(IEnumerable<T> content) {}
}
4

5 回答 5

7

您可以使用is来确定要使用的情况。

if (content is IEnumerable<T>)
    DoSomethingWithContent((IEnumerable<T>)content);
else
    DoSomethingWithContent(content);

如果你觉得很时髦,你可以通过强制转换为动态来使用运行时绑定器,但不建议这样做。

DoSomethingWithContent((dynamic)content);
于 2013-05-29T20:45:42.013 回答
2

IEnumerable<out T>协变的,所以如果你只是......

var enumerable = content as IEnumerable<T>;
if (enumerable == null)
    DoSomethingWithContent(content);
else
    DoSomethingWithContent(enumerable);

...DoSomethingWithContent(IEnumerable<T> content)即使实际运行时类型content是,它仍然会调用IEnumerable<C>,其中C继承T


这并没有解决您为什么首先尝试“适应IEnumerable<T>T

于 2013-05-29T20:57:31.610 回答
1

是的,您的设计存在循环问题。MyClass<T>例如,如果被初始化,MyClass<List<string>>那么T = List<string>重载的定义实际上不会被调用。你真正需要做的是只使用一个方法,但有一个子句来测试 if Timplements IEnumerable<T>。你可以这样做;

if (content is IEnumerable<T>)

我不完全确定这会起作用,因为您甚至可能必须指定 IEnumberable 使用的类型。如果是这种情况,请检查它是否实现了非泛型 IEnumberable,因为所有实现泛型版本的集合也实现了非泛型版本。

于 2013-05-29T20:48:53.927 回答
1

这行得通吗?

HttpResponseMessage Modify(HttpResponseMessage response) {
        T content;
        if(response.TryGetContentValue<T>(out content)) {
            DoSomethingWithContent(content);
        }
        else 
        {
           IEnumerable<T> content;
           if(response.TryGetContentValue<IEnumerable<T>>(out content)) {
            DoSomethingWithContent(content);
           }
        }
        return response;
    }
于 2013-05-29T21:11:05.507 回答
1

假设andDoSomething是同一件事(例如,一个委托给另一个) - 我认为总是使用 an 更有意义- 毕竟, a只是一个1 值。IEnumerable<T>TIEnumerable<T>TIEnumerable<T>

当然,这回避了TryGetContentValue只会给你返回 a T- 而不是IEnumerable<T>. 您可以通过先尝试T然后回退到IEnumerable<T>. 我认为将它作为一个对象拉出来并自己处理演员也可能会奏效。

所以 - 我认为你最终会得到类似的东西:

public class MyClass<T> {
    HttpResponseMessage Modify(HttpResponseMessage response) {
        IEnumerable<T> content = this.GetContent(response);
        DoSomethingWithContent(content);
        return response;
    }

    private IEnumerable<T> GetContent(HttpResponseMessage response) {
        object content;
        if (!response.TryGetContentValue(out content)) return new T[] { };
        if (content is T) return new T[] { (T)content };
        return content as IEnumerable<T> ?? new T[] { };
    }

    public void DoSomethingWithContent(IEnumerable<T> content) {
        foreach (var t in content) {
          // blah, blah
        }
    }
}

如果DoSomethingWithContent(T)并且DoSomethingWithContent(IEnumerable<T>)实际上是不同的 - 那么您基本上会遵循与GetContent做出分支决策相同的模式。

于 2013-05-29T21:14:42.157 回答