如何检查接口的特定类型

时间:2018-06-13 11:01:12

标签: c# interface

说我有这个对象

public class foo 
{
    Ibar data {get; set;}
}

public interface Ibar
{
    int id { get; set; }
}

public class bar : Ibar
{
    public int id {get; set;}
    public string a {get; set;}
}


public class bar2 : Ibar
{
    public int id {get; set;}
    public DateTime b {get; set;}
}

现在我在这里实现像这样的方法

public something Method(foo f)
{
    if(f.data is bar)
        Console.WriteLine(((bar)f.data).doSomething());
    else
        Console.WriteLine(((bar2)f.data).doSomething());
}

public string doSomething(this bar b)
{
    return b.a;
}

public string doSomething(this bar2 b)
{
    return b.b.ToString();
}

到目前为止一直很好(see)。有没有办法让这部分更优雅?特别是如果我有Ibar的多个实现,它会变得混乱......

    if(f.data is bar)
        Console.WriteLine(((bar)f.data).doSomething());
    else
        Console.WriteLine(((bar2)f.data).doSomething());

更新

所以doSomething应该是一种扩展方法。这就是为什么它没有在界面中定义。换句话说:我不允许更改界面或其实现。

3 个答案:

答案 0 :(得分:2)

您是否正在尝试专门的扩展课程?

假设您正在这样做。

然而,您可以使用dynamic

实现目标
public static class BarExtensions
{
  public static string Something(this Ibar b)
  {
      return doSomething((dynamic)b);
  }

  public static string doSomething( bar b)
  {
     return b.a;
  }

  public static string doSomething(bar2 b)
  {
     return b.b.ToString();
  }
}

因此,您只需要使用正确类型调用Something

此类型可以轻松获取任何对象的.GetType()(因此不会出现问题)

答案 1 :(得分:1)

我认为你可以在一个地方进行类型检查,因为这是多态性的一个很好的候选者。由于barbar2都实现了Ibar,因此您可以将doSomething的定义更改为以下内容。

public string doSomething(Ibar item)
{
    return item is bar ? ((bar)item).a : ((bar2)item).b.ToString();
}

现在,当您想要显示它时,这就是您处理foo的方式:

public void Method(foo f)
{
    Console.WriteLine(f.data);
}

您只需传递data属性,因为doSomething会在收到它时知道如何处理它。

<强>更新 根据您的评论,我正在扩展代码以使用我建议的模式匹配。请考虑以下

public string doSomething(Ibar item)
{
    switch (item)
    {
        case bar b:
            return b.a;
        case bar2 b:
            return b.b.ToString();
        case barX b:
            return b.X.ToString();
        default:
            return item.GetType().ToString(); // Just in case...
    }
}

其中barX的定义是

public class barX : Ibar
{
    public int id {get; set; }
    public object X {get; set; }
}

因此,每当您添加Ibar的实现时,您都会在doSomething中提供它。所有客户端代码都将保持不变,因为他们所要做的就是将Ibar传递给doSomething方法,该方法在上一个示例中使用模式匹配来确定项目的类型,并相应地起作用。

最终修改

看到你想要使用重载,你可以使用反射,但我不知道这是否符合你对优雅的定义。在这种情况下,它不会使用switch语句,并且只要它们处于写入的类型中就会找到你的方法。请考虑以下内容并更改我之前提供的DoSomething的定义。

public static string ProcessThings(Ibar item)
{
    var theType = item.GetType();
    Console.WriteLine(theType.Name);
    MethodInfo method = typeof(Program).GetMethods()
        .Where(x => x.IsStatic && x.Name == "DoSomething" && x.ToString().Contains(theType.Name))
        .SingleOrDefault();

    var ret = method.Invoke(null, new object[] { item });

    return ret?.ToString();
}

public static string DoSomething(barX item)
{
    return "foo";
}

public static string DoSomething(bar2 item)
{
    return "bar";
}

这样,您调用ProcessThings方法(为了简洁而重命名,但它仍然可以保留为DoSomething),它将确定要调用哪个重载。

答案 2 :(得分:0)

如果我记得很清楚你可以像generic type constraints这样玩:

public something Method<T>(T f) where T : IBar
{
    //Stuff here, where assures you f is always IBar
}

这应该强制传入的参数属于您想要的类型。 这是我能想到的最优雅的方式。

其他是typeof和其他条件语句,无论如何都需要更多的方法内代码(if,else等)。

修改 由于OP似乎很难理解,因此我使用Microsoft Unit Testing结果编写了一个完全正常工作的代码示例。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests_ALL
{
    [TestClass]
    public class UnrelatedTests
    {


        [TestMethod]
        public void InterfaceTest()
        {
            bar x = new bar { result = "Hi bar it's " };
            bar2 xx = new bar2 { beforeResult = DateTime.Now };

            Console.WriteLine(Method(x));
            Console.WriteLine(Method(xx));

        }

        public string Method<T>(T f) where T : Ibar
        {
            return f.result;
        }

    }

    public class foo
    {
        public foo(Ibar fooBar)
        {
            data = fooBar;
        }
        Ibar data { get; set; }
    }
    public interface Ibar
    {
        int id { get; set; }
        string result { get; set; }
    }

    public class bar : Ibar
    {
        public int id { get; set; }
        public string result { get; set; }
    }


    public class bar2 : Ibar
    {
        public int id { get; set; }
        public DateTime beforeResult
        {
            set { result = value.ToString(); }
        }
        public string result { get; set; }
    }

    public static class Extensions
    {

        public static string doSomething(this bar b)
        {
            return b.result;
        }

        public static string doSomething(this bar2 b)
        {
            return b.result;
        }
    }
}

这是输出:

enter image description here