C# 动态转换为IEnumerable<;T>;或T

C# 动态转换为IEnumerable<;T>;或T,c#,generics,reflection,C#,Generics,Reflection,我有一个类接受T,有一个方法接受HttpResponseMessage并修改响应中的内容 public class MyClass<T> { HttpResponseMessage Modify(HttpResponseMessage response) { T content; if(response.TryGetContentValue(out content)) { DoSomethingWithContent(

我有一个类接受
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) {}
}

您可以使用
is
来确定使用哪种情况

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

是的,你的设计有圆度问题。如果将
MyClass
初始化为例如
MyClass
,则
T=List
,因此实际上不会调用重载定义。实际上,您需要做的是只使用一个方法,但有一个子句来测试
T
是否实现了
IEnumerable
。你可以这样做

if (content is IEnumerable<T>)
if(内容是IEnumerable)
但我不完全确定这是否可行,因为您甚至可能需要指定IEnumberable使用的类型。如果是这种情况,那么检查它是否实现了非泛型IEnumerable,因为实现泛型版本的所有集合也实现了非泛型版本。

IEnumerable是协变的,因此如果您只是

var enumerable = content as IEnumerable<T>;
if (enumerable == null)
    DoSomethingWithContent(content);
else
    DoSomethingWithContent(enumerable);
var enumerable=内容为IEnumerable;
if(可枚举==null)
dosomethingwhithcontent(content);
其他的
含含量的dosomething(可枚举);
…即使
content
的实际运行时类型为
IEnumerable
,其中
C
继承
T
,它仍将调用
DoSomethingWithContent(IEnumerable content)


这并不能说明为什么您首先要在
t
中尝试“fit”
IEnumerable

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;
    }
HttpResponseMessage修改(HttpResponseMessage响应){
T含量;
if(response.TryGetContentValue(输出内容)){
dosomethingwhithcontent(content);
}
其他的
{
可数内容;
if(response.TryGetContentValue(输出内容)){
dosomethingwhithcontent(content);
}
}
返回响应;
}

假设
DoSomething
对于
IEnumerable
T
是一样的(例如,一个委托给另一个)-我认为总是使用
IEnumerable
-毕竟,
T
只是一个带有1个值的
IEnumerable

当然,这避免了
TryGetContentValue
只会返回
T
——而不是
IEnumerable
的问题。您可以先尝试
T
,然后返回到
IEnumerable
。我认为把它作为一个物体拿出来,自己处理演员也可以

所以-我想你最终会得到这样的结果:

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
        }
    }
}
公共类MyClass{
HttpResponseMessage修改(HttpResponseMessage响应){
IEnumerable content=this.GetContent(响应);
dosomethingwhithcontent(content);
返回响应;
}
私有IEnumerable GetContent(HttpResponseMessage响应){
对象内容;
if(!response.TryGetContentValue(out content))返回新的T[]{};
如果(内容为T),则返回新的T[]{(T)内容};
将内容返回为IEnumerable??新的T[]{};
}
公共void DoSomethingWithContent(IEnumerable content){
foreach(内容中的var t){
//废话,废话
}
}
}

如果
DoSomethingWithContent(T)
DoSomethingWithContent(IEnumerable)
实际上是不同的,那么您基本上应该遵循与
GetContent
相同的模式来做出分支决策。

您在寻找这个吗@罗伯塔维:我不认为这里发生了什么。好吧,值得一试。一般来说,当我问自己这样的问题时,是因为我没有尽我所能设计好东西。如果你能将代码重构为不需要任何运行时测试,这可能值得一看。@CoryNelson我同意你的观点-首先要让它工作,然后再重构:)事实上,我非常喜欢这个想法。我们来考虑一下这个问题,但是内容声明呢。现在,在尝试获取内容值之前,我有
T content
,但
DoSomethingWithContent
接受
T
IEnumerable
。将内容声明为对象会导致
无法解析方法…,候选对象是…
如果您想声明
对象内容
,那么您可以使用
T
进行相同的测试和强制转换,正如我在
IEnumerable
中所示。问题不是关于
IEnumerable
IEnumerable
的关系。它是关于
IEnumerable
vs
T
@recursive的,这是
as
在运行时测试的内容。谢谢你,马克
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;
    }
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
        }
    }
}