我有一个接受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()
的情况下,T
将返回false {{1} }}不是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) {}
}
答案 0 :(得分:7)
您可以使用is
来确定要使用的案例。
if (content is IEnumerable<T>)
DoSomethingWithContent((IEnumerable<T>)content);
else
DoSomethingWithContent(content);
如果你感觉很时髦,你可以通过强制转换来使用运行时绑定器,但不建议这样做。
DoSomethingWithContent((dynamic)content);
答案 1 :(得分: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
。< / p>
这不能解决为什么你首先在IEnumerable<T>
中尝试“适合”T
?
答案 2 :(得分:1)
是的,您的设计存在圆形问题。如果MyClass<T>
被初始化为例如MyClass<List<string>>
,那么T = List<string>
,因此实际上不会调用重载的定义。您实际需要做的只是使用单个方法,但有一个子句来测试T
是否实现IEnumerable<T>
。你可以这样做;
if (content is IEnumerable<T>)
我不完全确定它会起作用,因为你甚至可能必须指定IEnumberable使用的类型。如果是这种情况,那么检查它是否实现了非通用IEnumberable,因为实现通用版本的所有集合也实现了非通用版本。
答案 3 :(得分: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;
}
答案 4 :(得分:1)
假设DoSomething
对IEnumerable<T>
和T
是相同的(例如,一个委托给另一个) - 我认为总是使用一个更有意义IEnumerable<T>
- 毕竟,T
只是IEnumerable<T>
,只有1个值。
当然,这可以回避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
相同的模式来做出分支决策。