繁体   English   中英

运行时通用方法检查参数

[英]Generic method check parameter in runtime

public override void Test<T> T input)
{
  if(input is TypeA)
   {
    var expected =input as TypeA;
     foreach(var a in expected.Values)
     {
       // long process
     }

    }


    else
    {
     var expected =input as TypeB;
     foreach(var a in expected.Values)
     {
       //long process
     }
    }

我如何声明expected以便我不必两次编写 foreach 语句? TypeA 和 TypeB 没有任何关系。

鉴于没有TypeATypeB实现的通用类型,您可以这样做:

public void Test<T>(T input)
{
    var expectedA = input as TypeA;
    if (expectedA != null)
    {
        Process(expectedA.Values);
    }

    var expectedB = input as TypeB;
    if (expectedB != null)
    {
        Process(expectedB.Values);
    }
}

private void Process(IEnumerable<Something> values)
{
    // long process
}

或者使用模式匹配:

public void Test<T>(T input)
{
    if (input is TypeA expectedA)
    {
        Process(expectedA.Values);
    }

    if (input is TypeB expectedB)
    {
        Process(expectedB.Values);
    }
}

但是如果我们不检查类型会更好。 这意味着input几乎可以是任何东西,也许不是TypeATypeB 方法最好只关心参数的声明类型。 因此,如果您创建了这样的界面:

public interface IHasWhateverTheseValuesAre
{
    IEnumerable<Something> Values { get; set; }
}

TypeATypeB都可以实现它。 然后你的方法看起来像这样:

public void Test<T>(T input) where T : IHasWhateverTheseValuesAre
{
    foreach (var value in input.Values)
    {
        // whatever
    }
}

该方法不关心输入是TypeATypeB还是任何其他类型,因此不需要检查。 它只会在您传递实现IHasWhateverTheseValuesAre东西时编译,因此参数将始终具有该Values属性。


你提到

这些类型是通过 XSD 创建的,并且在反序列化时以任何方式关联它们都会产生问题。

那应该没关系。 如果你有一个TypeATypeB的对象,这意味着它已经被反序列化了。 让这两个类实现一个公共接口(根本不会改变它们)不会影响到这一点。


另一种看待它的方式:

如果此方法对一组值进行操作,它是否应该将TypeATypeB作为参数?

也许它应该看起来像这样:

public void Test(IEnumerable<Something> values)
{
    foreach (var value in values)
    {
        // whatever
    }
}

您可以使用类型dynamic

public override void Test(object input)
{
 dynamic expected = input;
 if(input is TypeA)
 {
 foreach(var a in (expected as TypeA).Values)
 {
   // long process
 }

}

else
{
 foreach(var a in (expected as TypeB).Values)
 {
   //long process
 }
}

你可以让它更通用。

switch (expected.GetType())
{
  case "TestA":
  //do something
  break;

  case "TestA":
  //do something
  break;

  default:
  throw new Exception("unexcepted Type!");
 }

如果您确定类型,您可以创建一个实现值列表的接口,然后将该接口作为参数传递,但它不是通用的,每次您应该更改类的实现时,您必须确保具有相同的属性。

希望能帮助到你!

一种解决方案是只编写一个方法(假设两个a不是同一类型):

private static void MyForEachLoop<T>(IEnumerable<T> enumerable) {
    foreach (var a in enumerable) {
        // long process
    }
}

或者,如果a s 属于相同类型,则不需要泛型:

private static void MyForEachLoop(IEnumerable<CommonTypeOfTheAs> enumerable) {
    foreach (var a in enumerable) {
        // long process
    }
}

像这样调用它:

if(input is TypeA)
{
    var expected = input as TypeA;
    MyForEachLoop(expected.Values);
}
else
{
    var expected = input as TypeB;
    MyForEachLoop(expected.Values);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM