15

EDIT

The bare-bones version of this question is, if I have some object o, how would I check to see if o is of some type that implements IEnumerable<string> with reflection? The original question is much more specific, but an answer to the above would be just as good. Sorry if I gave too much detail on this question

END EDIT

The following is a contrived ValueInjecter POC. Everything works well except for the isCollectionMapping method at the very bottom. I'm trying to get it to return true if and only if both the source and target property are any object that implement IEnumerable<respectiveTypes>.

I've tried IsAssignableFrom and also IsInstanceOfType, but neither seems to work.

Everything else works since when I uncomment the second line of the method to check explicitly for properties of name "Children", it works fine.

Note - I do know there are issues with this example. Namely, I'm trying to check for any old IEnumerable<> but yet always knowing enough to return List<>; it's just a silly proof of concept at this point.

[TestClass]
public class UnitTest1 {

    [TestMethod]
    public void TestMethod1() {
        List<string> strings = new List<string>();

        Subject S = new Subject() {
            id = 1,
            SubjectName = "S1",
            Children = { new Subject() { id = 2, SubjectName = "S1a" },
                         new Subject() { id = 3, SubjectName = "S1b", Children = { new Subject() { id = 4} } } }
        };

        SubjectViewModel VM = (SubjectViewModel)new SubjectViewModel().InjectFrom<CollectionToCollection>(S); ;


        Assert.AreEqual(2, VM.Children.Count);
        Assert.AreEqual(1, VM.Children.Single(s => s.id == 3).Children.Count);
    }
}


public class Subject {
    public Subject() {
        Children = new List<Subject>();
    }

    public string SubjectName { get; set; }
    public int id { get; set; }

    public List<Subject> Children { get; set; }
}

public class SubjectViewModel {
    public SubjectViewModel() {
        Children = new List<SubjectViewModel>();
    }

    public string SubjectName { get; set; }
    public int id { get; set; }

    public List<SubjectViewModel> Children { get; set; }
}

public class CollectionToCollection : Omu.ValueInjecter.ConventionInjection {
    protected override bool Match(ConventionInfo c) {
        return c.TargetProp.Name == c.SourceProp.Name;
    }

    protected override object SetValue(ConventionInfo c) {
        if (isCollectionMapping(c))
            return (c.SourceProp.Value as IEnumerable<Subject>).Select(s => (SubjectViewModel)(new SubjectViewModel().InjectFrom<CollectionToCollection>(s))).ToList();
        else
            return c.SourceProp.Value;
    }

    private bool isCollectionMapping(ConventionInfo c) {
        return c.SourceProp.Value.GetType().IsInstanceOfType(typeof(IEnumerable<Subject>)) && c.TargetProp.Value.GetType().IsAssignableFrom(typeof(IEnumerable<SubjectViewModel>));

        //return c.SourceProp.Name == "Children" && c.TargetProp.Name == "Children";
    }
}
4

3 回答 3

32

如果我有一些对象o,我将如何检查是否o是某种实现的类型IEnumerable<string>

很简单:

o is IEnumerable<string>

顺便说一句,您当前的代码不起作用,因为它正在反转可分配性关系的测试(就像调用了该方法一样IsAssignableTo),即假设:

Bar bar = ...
Foo foo = bar

暗示:

typeof(Bar).IsAssignableFrom(typeof(Foo)) // wrong

实际上,实际含义是:

typeof(Foo).IsAssignableFrom(typeof(Bar))

也就是说,我正在尝试检查任何旧的IEnumerable<>

在这种情况下,您需要测试该类型是否实现了泛型接口的构造版本:

o.GetType()
 .GetInterfaces()
 .Any(t => t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
于 2011-04-06T14:19:34.927 回答
10

The bare-bones version of this question is, if I have some object o, how would I check to see if o is of some type that implements IEnumerable<string>?

Like this:

object o = whatever;
bool isSequenceOfStrings = o is IEnumerable<string>;
于 2011-04-06T14:17:59.997 回答
5

我可能错过了一些东西(没有阅读您的整个代码示例),但您似乎不需要在这里反思。

如何只使用:

if (c.SourceProp.Value is IEnumerable<Subject>)
   return true;

如果您不知道具体类型,请使用泛型:

public bool MyFunction<T>(...)
{
   if (c.SourceProp.Value is IEnumerable<T>)
      return true;
}

或者,如果您需要使用接口,请这样做(节省演员表):

var enumerable = c.SourceProp.Value as IEnumerable<string>;
if (enumerable != null)
{
   // Use IEnumerable<string>
   return true;
}

return false;
于 2011-04-06T14:19:51.160 回答