【问题标题】:Can an object be cast to two unrelated types?一个对象可以转换为两种不相关的类型吗?
【发布时间】:2021-07-19 21:54:36
【问题描述】:

我有一种情况,我收到的对象只能是两种已知类型之一 - 我们称它们为“typeA”和“typeB”。这两种类型互不相关。

我需要先找到正确的类型才能使用该对象。下面是一些代码,显示了我最初尝试找到正确类型的尝试:

    public void OneOfTwoTypes(object obj)
    {
        try 
        { 
            var objType = (typeA)obj; 
        }
        catch (InvalidCastException)
        {
            var objType = (typeB)obj; 
        }

        // extra code for doing things to this object. 

    }

上面的代码由于作用域而无法运行。而且我也不能将 var 声明为 null 。所以我选择了动态:

    public void OneOfTwoTypes(object obj)
    {
        dynamic objType;
        try 
        { 
            objType = (typeA)obj; 
        }
        catch (InvalidCastException)
        {
            objType = (typeB)obj; 
        }

        // extra code for doing things to this object. 

    }

这运行良好并且可以完成工作。我的问题是 - 有没有更好的方法来做到这一点?另外,之前没有使用过动态,我当前的实现是否有任何重大问题?

编辑:围绕对象的用途添加一些评论。 typeA 和 typeB 对象实现了相似的属性,但代表不同的物理实体(一个代表施加的压力,另一个代表点载荷)。对于上面的代码,我将使用非常相似的属性(例如 typeA.propertyA 表示来自雪的压力载荷,并且在概念上与 typeB.propertyA 相似,因为两者都来自雪载荷,但后者指的是点载荷。请注意,两者确实有一些不同的属性。

最终输出将是负载组合的计算 - 无论使用 typeA 还是 typeB,这将包括相同类型的计算。

我不想使用方法重载,因为这将涉及为两种对象类型复制大量相同的代码(我们在这里谈论数百行)。我确实喜欢两种类型都实现的接口的想法。

【问题讨论】:

  • 更好的办法是引入typeA和typeB都实现的接口。
  • 我不明白:如果您在try 之外不知道类型,您打算如何处理该对象?请说明您在投射后要达到的目标。另外:您应该使用as 安全地强制转换而不会引发异常,或者更好的是is typeA objType 将其直接分配给变量
  • 使用dynamic objType,您不必强制转换object obj,只需将其分配给dynamicThe question is,选角给了你什么?然后你会根据它们的类型对这些对象调用不同的方法吗?
  • 您的字面问题的答案可在重复项(以及许多其他项)中找到。您的问题中没有足够的上下文来了解您决定使用的解决方案是否真的合适。例如,如果该方法的调用者已经具有正确的类型,那么使用方法重载比运行时类型检查要好得多。如果对象具有相似的功能,那么使用接口比运行时类型检查要好得多。坦率地说,几乎任何事情都比运行时类型检查好得多。有时无法避免,但大多数时候可以。
  • 感谢大家的建议。我添加了一个编辑来解释更多。我确实喜欢你的推荐@mjwills,所以可能会朝那个方向发展。

标签: c#


【解决方案1】:

首先,c# 并不是真正构建将对象作为对象传递的。强类型语言的最大好处之一是,当我想要一个列表时,获取一个数组对象并不令人意外,反之亦然。您的第一个选择应该是一个共享接口,两者都可以实现,您可以作为接口而不是显式实现传递。

但有时这并不总是有效。在这种情况下,您仍然可以选择。

像 c# 这样的语言在运行时也知道对象类型。基本的 api 是 obj.GetType() == typeof(TypeA),但只有在类型相同并且不考虑继承关系或接口实现时才会评估为 true。然后起点是obj is TypeA,如果可以为对象分配TypeA 类型,则返回true,否则返回false。这也可以在 if 语句中使用(见下文)。

如果您需要测试不止一种或两种类型,也可以使用 C# 8 中的 pattern matching switch

// we'll pretend for this example that array and list of 2 completely different objects that need to be handled in code in completely different ways
var obj = new Random().Next(2) == 1
    ? (IEnumerable<Guid>) new []{ Guid.NewGuid() }
    : new List<Guid> { Guid.NewGuid() };

// option 1: if statements with `is` keyword
if (obj is List<Guid> list)
{
    // the variable list in in scope in the if block, since it was declared in the if statement
    HandleList(list);
}
else if (obj is Guid[] array)
{
    // the variable array is in scope in the else block
    HandleArray(array);
}


// option 2: pattern matching switch
switch (obj) 
{
    case List<Guid> list:
        HandleList(list);
        break;
    case Guid[] array:
        HandleArray(array);
        break;
    default:
        throw new ArgumentOutOfRangeException();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-04
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多