我有一个接受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) {}
}
像这样使用…
只要响应内容值是类型T
, ,但有时它是IEnumerable<T>
,当这种情况下,TryGetContentValue()
将返回false,因为T
不是IEnumerable<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) {}
}
您可以使用is
来确定使用哪种情况
if (content is IEnumerable<T>)
DoSomethingWithContent((IEnumerable<T>)content);
else
DoSomethingWithContent(content);
如果你觉得很时髦,你可以通过强制转换为dynamic来使用运行时绑定,但不建议这样做。
DoSomethingWithContent((dynamic)content);
IEnumerable<out T>
是协变,所以如果你只是…
var enumerable = content as IEnumerable<T>;
if (enumerable == null)
DoSomethingWithContent(content);
else
DoSomethingWithContent(enumerable);
…即使content
的实际运行时类型是IEnumerable<C>
,它仍然会调用DoSomethingWithContent(IEnumerable<T> content)
,其中C
继承了T
。
这并没有解决为什么你在T
中尝试"适合"IEnumerable<T>
?
是的,你的设计存在循环问题。如果MyClass<T>
被初始化为MyClass<List<string>>
,那么T = List<string>
实际上不会被调用重载定义。您实际需要做的是只使用一个方法,但是有一个子句来测试T
是否实现了IEnumerable<T>
。你可以这样做;
if (content is IEnumerable<T>)
我不完全确定这是否有效,因为你甚至可能必须指定IEnumberable使用的类型。如果是这种情况,那么检查它是否实现了非泛型IEnumberable,因为所有实现泛型版本的集合也实现了非泛型版本。
这个行吗?
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;
}
假设DoSomething
对于IEnumerable<T>
和T
是相同的事情(例如:(一个委托给另一个)-我认为总是使用IEnumerable<T>
更有意义-毕竟,T
只是一个具有1值的IEnumerable<T>
。
当然,这回避了TryGetContentValue
只会给你一个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
相同的模式来做出分支决策。