检查对象是否为相同类型

78

你好,我需要知道如何在C#中检查是否为同一类型的对象。

场景:

class Base_Data{}

class Person : Base_Data { }
class Phone  : Base_data { }

class AnotherClass
{
   public void CheckObject(Base_Data data)
   {
         if (data.Equals(Person.GetType()))
         { //<-- Visual Studio 2010 gives me error, says that I am using 'Person' is a type and not a variable.

        }
    }
}

2
在我看来:请重新考虑这种设计。你的方法要么适用于“Base_Data”类型,要么适用于子类“Person”和“Phone”。如果“CheckObject”确实有不同的事情发生,为什么不重载该方法,并拥有单独的“CheckObject(Phone phone)”和“CheckObject(Person person)”方法呢?这不需要太多额外的代码,而且能够在编译时检查传递给“CheckObject”的“Base_Data”子类是否被支持。 - mlibby
4个回答

144
你可以使用is运算符:
if (data is Person)
{
    // `data` is an instance of Person
}

另一个可能性是使用as运算符

var person = data as Person;
if (person != null)
{
    // safely use `person` here
}

或者,从C# 7开始,使用一种类型模式匹配的is运算符形式结合上述两者:

if (data is Person person)
{
    // `data` is an instance of Person,
    // and you can use it as such through `person`.
}

在第二个例子中,如果为假,是否应该抛出异常?如果是,是什么类型的异常? - jth41
@jth41,如果需要这种行为,请使用常规转换(Person person = (Person)data;)而不是安全转换。 - ANeves

27

这取决于你想要的具体内容。使用isas(如Darin的回答所示)将告诉你data是否是Person的实例或其子类型。这是最常见的形式(尽管如果你可以设计避免需要它,那将更好) - 如果这正是你需要的,那么Darin的答案是应该采用的方法。

然而,如果你需要一个精确匹配 - 如果你不希望在data指向从Person派生的某个类的实例时执行特定操作,只对Person本身执行操作,那么你需要像这样的代码:

if (data.GetType() == typeof(Person))

这是相对罕见的情况- 这时候值得质疑你的设计。


在 switch 中实现类类型检查是否可行?还是只能用 if、else if 的方式? - Pierre
2
@Pierre:从C# 7开始,您可以在switch语句中使用模式,包括类型模式。 - Jon Skeet

11

让我们逐步解决这个问题。第一步是必需的,接下来的两步是可选但建议执行的。

第一次纠正(必需)确保您不将某种类型的对象与System.Type类型的对象进行比较:

if (data.GetType().Equals(typeof(Person))) ...
//      ^^^^^^^^^^
//      add this to make sure you're comparing Type against Type, not
//      Base_Data against Type (which caused the type-check error)!

其次,将此简化为:

if (data is Person) ... // this has (almost) the same meaning as the above;
                        // in your case, it's what you need.

第三步,完全摆脱 if 语句!这可以通过使用多态性(或更准确地说,方法重写)来实现,例如:

class Base_Data
{
    public virtual void Check() { ... }
}

class Person : Base_Data
{
    public override void Check()
    {
        ... // <-- do whatever you would have done inside the if block
    }
}

class AnotherClass
{
    public void CheckData(Base_Data data)
    {
         data.Check();
    }
}

正如你所看到的,条件式的代码已经被转移到了Base_Data类和它的派生类PersonCheck方法中。不再需要这样的类型检查if语句了!


2

这个问题的意图有点不清楚,但我找到了一个与之相关的问题,寻找一种检查两个对象是否为相同类型的方法。以下是我的解决方案以及一些测试,所有测试都通过:

using NUnit.Framework;

[TestFixture]
public class TypeEqualityChecks
{
    class Base_Data { }

    class Person : Base_Data { }
    class Phone  : Base_Data { }

    class AnotherClass
    {
        public static bool CheckObjects(Base_Data d1, Base_Data d2) {
            return d1.GetType() == d2.GetType();
        }
    }
    
    [Test]
    public static void SameTypesAreEqual() {
        Base_Data person1 = new Person();
        Base_Data person2 = new Person();
        Assert.IsTrue(AnotherClass.CheckObjects(person1, person2));
    }
    
    [Test]
    public static void DifferentActualTypesAreNotEqual() {
        Base_Data person = new Person();
        Base_Data phone = new Phone();
        Assert.IsFalse(AnotherClass.CheckObjects(person, phone));
    }
    
    [Test]
    public static void BaseTypeAndChildTypeAreNotEqual() {
        Base_Data baseData = new Base_Data();
        Base_Data person = new Person();
        Assert.IsFalse(AnotherClass.CheckObjects(baseData, person));
    }
}

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