将接口转换为其实现

时间:2018-08-14 22:29:32

标签: c#

我有一个接口,该接口由存储了更多信息的更多类实现。而且我需要能够转换实现,而不必明确地说这是一个实现。

public interface IAnimal
{
    string Name { get; set; }
    Type GetType();
}

public class Dog : IAnimal
{
    public string Name { get; set; }
    Type GetType() {return typeof(Dog);}
    public int TimesBarked { get; set; }
}

public class Rhino : IAnimal
{
    public string Name { get; set; }
    Type GetType() {return typeof(Rhino);}
    public bool HasHorn { get; set; }
}

在大多数代码中,我毫无问题地使用该接口,但是在某些时候,我需要将实现强制转换为其原始类型。

IAnimal animal = new Dog
{
    Name = "Ben",
    TimesBarked = 30
}
// Doing stuff with Ben

// In some other function
AnotherObject.SomeMethodThatNeedsToKnowType(animal) //Needs to be Converted before putting here

我不知道会得到哪个对象,所以我必须做一些可以将任何东西转换成原始类型的东西。 不幸的是,Convert.ChangeType(animal, animal.GetType())返回object{Dog}而不是Dog。我可以更改接口及其实现,但不能更改Method。

3 个答案:

答案 0 :(得分:5)

  

我不知道我会得到哪个对象,所以我不得不做些可以将任何东西转换为原始类型的东西。

那您打算怎么做 ?由于您不知道类型,因此您不知道可以调用什么方法,等等。这就是为什么原始解决方案返回object的原因。

您可以使用dynamic,但如果尝试使用不存在的方法,则会抛出该错误。最接近的结果就是简单的is检查(为简便起见,使用C#7模式匹配):

if (animal is Dog dog) 
   //Do stuff with dog
else if (animal is Rhino rhino)
   // Do stuff with rhino

重大免责声明:垂头丧气是一个巨大的危险信号。当您什至不知道期望哪种类型时,向下转换就更糟了。您的设计几乎肯定需要重新考虑。

答案 1 :(得分:1)

不确定,您的最终结局是什么。如果您不想使用IS和AS,我可能会...不管怎样:

using System;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public interface IAnimal
        {
            string Name { get; set; }
            //Type GetType();
        }

        public class Dog : IAnimal
        {
            public string Name { get; set; }
            //new Type GetType() { return typeof(Dog); }
            public int TimesBarked { get; set; }
        }

        public class Rhino : IAnimal
        {
            public string Name { get; set; }
            //new Type GetType() { return typeof(Rhino); }
            public bool HasHorn { get; set; }
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IAnimal animal1 = new Dog { Name = "Ben", TimesBarked = 30 };
            IAnimal animal2 = new Rhino { Name = "James" };

            MessageBox.Show($"GetType : {animal1.GetType()}");

            PeopleWillTellYouToNotDoThis(animal1);
            PeopleWillTellYouToNotDoThis(animal2);
        }

        private void PeopleWillTellYouToNotDoThis(dynamic inAnimal)
        {
            MessageBox.Show($"GetType : {inAnimal.GetType()}");

            //The following works.  But, you should probably really use 'IS' to see if you have a RHINO or not
            try { MessageBox.Show($"HasHorn : {inAnimal.HasHorn}"); } catch { };
        }
    }
}

答案 2 :(得分:1)

全新的C#功能,“模式匹配”开关语句(请查看底部的the Switch Statement docs)可以为您提供帮助。

我一起经历了一个快速接口和几个实现该接口的类:

public interface IAnimal
{
    string Speak();
}

public class Cat : IAnimal
{
    public string Speak()
    {
        return "Meow";
    }
}

public class Dog : IAnimal
{
    public string Speak()
    {
        return "Woof";
    }
}

然后,我创建了IAnimal的集合,并使用switch语句找出了什么:

  var animals = new List<IAnimal>
  {
      new Cat(), new Dog(), new Cat()
  };

  foreach (var animal in animals)
  {
      switch (animal)
      {
          case Cat cat:
              Debug.WriteLine("This is a cat");
              break;
          case Dog dog:
              Debug.WriteLine("This is a dog");
              break;
      }
  }

输出如下:

  

这是一只猫

     

这是一条狗

     

这是一只猫

我没有显示它,但是catdog变量是很好的,类型正确的对象引用,可以在范围内使用它们。

但是,正如@BradleyDotNET所提到的,这通常表明设计或实现不正确。

相关问题