检查 IEnumerable有反射

发布于 2024-10-30 05:32:25 字数 2814 浏览 0 评论 0原文

编辑

这个问题的基本版本是,如果我有一些对象o,我将如何检查o是否是实现IEnumerable<的某种类型;string> 带有反射?最初的问题更加具体,但对上述问题的回答也同样好。抱歉,如果我在这个问题上提供了太多细节

END EDIT

以下是一个人为的 ValueInjecter POC。除了最底部的 isCollectionMapping 方法之外,一切都运行良好。我试图让它返回 true 当且仅当源属性和目标属性都是实现 IEnumerable 的任何对象时。

我尝试过 IsAssignableFromIsInstanceOfType,但似乎都不起作用。

其他一切都有效,因为当我取消注释该方法的第二行以显式检查名称“Children”的属性时,它工作正常。

注意 - 我确实知道这个示例存在问题。也就是说,我试图检查任何旧的 IEnumerable<> 但始终知道足够的信息来返回 List<>;目前这只是一个愚蠢的概念证明。

[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";
    }
}

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";
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花间憩 2024-11-06 05:32:25

如果我有一些对象o,我会怎么做
检查 o 是否属于某种类型
实现 IEnumerable

简单如下:顺便

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<>))

If I have some object o, how would I
check to see if o is of some type that
implements IEnumerable<string>?

As simple as:

o is IEnumerable<string>

By the way, your current code isn't working because it is reversing the testing of the assignability relationship (as though the method were called IsAssignableTo), i.e. It is assuming that:

Bar bar = ...
Foo foo = bar

implies:

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

In reality, the actual implication is that:

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

Namely, I'm trying to check for any
old IEnumerable<>:

In this case, you need to test if the type implements a constructed version of the generic interface:

o.GetType()
 .GetInterfaces()
 .Any(t => t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
老子叫无熙 2024-11-06 05:32:25

这个问题的简单版本是,如果我有一些对象 o,我如何检查 o 是否是实现 IEnumerable 的某种类型?

像这样:

object o = whatever;
bool isSequenceOfStrings = o is IEnumerable<string>;

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>;
一身软味 2024-11-06 05:32:25

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

直接使用怎么样:

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;

I could have missed something (didn't read your whole code sample), but it doesn't seem like you need reflection here.

How about just using:

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

If you don't know the specific type, use generics:

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

Or if you need to use the interface, do it this way (saves a cast):

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

return false;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文