如何使用反射确定属性类型?

38

我该如何测试一个类型的属性是否为指定类型?

编辑:我的目标是检查一个程序集,看看其中是否有任何类型包含MyType(或从MyType继承)的属性。

以下是我所走过的路径...

AssemblyName n = new AssemblyName();
n.CodeBase = "file://" + dllName;
Assembly a = AppDomain.CurrentDomain.Load(n);

foreach (Type t in a.GetTypes())
    foreach (PropertyInfo pi in t.GetProperties())
        if ( pi.PropertyType is MyType ) // warning CS0184
            Console.WriteLine("Found a property that is MyType");

这段代码编译时会提示警告 CS0184: 提供的表达式永远不是 'MyType' 类型。
8个回答

59

您对哪种类型感兴趣?是方法/属性/事件等的返回类型吗?

如果是这样,我认为在MemberInfo中没有任何东西可以让您直接获取它 - 您需要强制转换并使用MethodInfo.ReturnTypePropertyInfo.PropertyTypeFieldInfo.FieldTypeEventInfo.EventHandlerType以及我忘记的其他任何内容。(请记住,类型本身可以是成员。不确定您想要做什么!)

编辑:如果您对特定类型是否表示MyType或某个子类感兴趣,则使用Type.IsAssignableFrom

if (typeof(MyType).IsAssignableFrom(type))

编辑:现在我们知道您想要属性,很容易 - 使用GetProperties而不是GetMembers。我喜欢使用LINQ进行反射:

var query = from type in assembly.GetTypes()
            from property in type.GetProperties()
            where typeof(MyType).IsAssignableFrom(property.PropertyType)
            select new { Type=type, Property=property };

foreach (var entry in query)
{
    Console.WriteLine(entry);
}

如果你不喜欢LINQ:

foreach (Type t in a.GetTypes())
    foreach (PropertyInfo pi in t.GetProperties())
        if (typeof(MyType).IsAssignableFrom(pi.PropertyType))
            Console.WriteLine("Found a property that is MyType");

请注意,您可能需要指定绑定标志以获取非公共属性等。

我应该说“属性”而不是“成员”。我已经更新了问题,希望现在更清晰了。 - Ed Guiness
@Jon Skeet:不相关的话题:你看过FinalBuilder广告吗?相当有趣! - Mitch Wheat
1
@Mitch:是的。他们也很客气地问了我是否可以。 - Jon Skeet

48

好的,也许我太蠢了,但是应该是这样的:

if ( pi.PropertyType == typeof(MyType ))

???


1
如果你的类型是通用的(例如 DbSet<>),你可以尝试这样做。if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)) { ... } - timothy
这比被接受的答案更有意义。type.IsAssignableFrom() 看起来(我自己没有测试过)如果该类型继承自另一个基类或接口,则可以匹配另一个类型。例如:List<T> 可以 IsAssignableFrom IEnumerable<T>,反之亦然。 - revobtz

2

有多种方式可以测试对象的类型:

1)使用is运算符:

if (anObject is MyType) {
// anObject is MyType or a derived class
... 
}

2) 使用 as 运算符:

MyType newObject = anObject as MyType;
if (newObject != null ) {
// newObject is anObject cast to MyType
...
}

3) 使用typeof()和GetType() [3种变体]:

// #1
if (typeof(MyType) == anObject.GetType()) {
// anObject is a MyType
...
}

//#2
public static bool IsType(object obj, string type)
{// modified from Visual C# 2005 Recipes {Apress}
// Get the named type, use case-insensitive search, throw
// an exception if the type is not found.
Type t = Type.GetType(type, true, true);
return t == obj.GetType();
}

//#3
public static bool IsTypeOrSubclass(object obj, string type)
{// modified from Visual C# 2005 Recipes {Apress}
// Get the named type, use case-insensitive search, throw
// an exception if the type is not found.
Type t = Type.GetType(type, true, true);
return t == obj.GetType() || obj.GetType().IsSubclassOf(t);
}

1

您正在寻找:

if (typeof(mi) is MyType) { ... }

对吧?


这样做不行,因为typeof(mi)的类型是Type而不是MyType。 - HAL9000

1
这个例子来自另一个类似的问题,让我更容易理解了。
如果p.PropertyType是GetType(String)。

1
我认为你需要类似这样的东西:
using System;
using System.Reflection;

namespace ConsoleApplication1{
    class Class1{

        static bool checkType(Type propertyType,Type myType){
            if (propertyType == myType){
                return true;
            }
            Type test = propertyType.BaseType;
            while (test != typeof(Object)){
                if (test == myType){
                    return true;
                }
                test = test.BaseType;
            }
            return false;
        }

        [STAThread]
        static void Main(string[] args){
            Assembly a = Assembly.GetExecutingAssembly();
            foreach (Type t in a.GetTypes()){
                Console.WriteLine("Type: {0}",t.Name);
                foreach (PropertyInfo p in t.GetProperties()){
                    if (checkType(p.PropertyType,typeof(MyType))){
                        Console.WriteLine("  Property: {0}, {1}",p.Name,p.PropertyType.Name);
                    }
                }
            }
        }
    }

    class MyType{
    }

    class MyType2 : MyType{
    }

    class TestType
    {
        public MyType mt{
            get{return _mt;}
            set{_mt = value;}
        }
        private MyType _mt;
        public MyType2 mt2
        {
            get{return _mt2;}
            set{_mt2 = value;}
        }
        private MyType2 _mt2;
    }
}

我收到的警告是CS0184:给定的表达式永远不是所提供类型的。 - Ed Guiness
那是因为它的类型是System.Type...检查一下我的代码,希望能有所帮助。 - Paolo Tedesco

0

在比较一个实例与明确写出的类型时,应该使用is

Department sales = new Department("Sales");

Debug.Assert(sales is Department);

当你想比较两种类型并且无法明确写出类型时,应该使用 typeof:

private void CheckType(Type t)
{
    Debug.Assert(typeof(Department) == t);
}

is 会考虑继承,而 typeof 不会。

public class Animal { }
public class Dog : Animal { }

public void Test()
{
    Dog d = new Dog();

    Debug.Assert(d is Animal); // true

    Debug.Assert(typeof(Dog) == typeof(Animal); // false
}

如果您想比较两种类型并考虑继承关系,可以使用IsAssignableFrom
Debug.Assert(typeof(Animal).IsAssignableFrom(typeof(Dog))); // true

0

这是一种快捷方式

property.PropertyType.IsGenericType && (typeof(ICollection<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
&& typeof(<YourType>).IsAssignableFrom(property.PropertyType.GenericTypeArguments[0])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接