【问题标题】:How to use a switch statement to compare references如何使用 switch 语句来比较引用
【发布时间】:2021-06-25 01:09:54
【问题描述】:

我正在尝试匹配对结构中字段的引用,但我不确定如何将其作为案例设置而不是 if 语句。

这是我对 if 语句所做的总体思路:

public struct Test
{
   // MyObject is a class
   public MyObject A;
   public MyObject B;
   public MyObject C;

   public bool Distance(MyObject obj, out float distance){
        distance = float.PositiveInfinity;
        if(A == obj){
         distance = DistanceFrom(A);
         return true;
        }
        if(B == obj){
         distance = DistanceFrom(B);
         return true;
        }
        if(C == obj){
         distance = DistanceFrom(C); 
         return true;
        }
        //object does not relate to this struct so return false
        return false;
   }
}

在我的实际结构中有超过 3 个(总共 24 个),但我想知道如何通过 case 语句来进行比较,因为它比许多 if 语句要干净得多。另外,我不希望使用我的 24 个引用的列表,因此不希望使用简单的 for 循环来运行它,因为我最终会将我的结构分配给堆。

是否可以切换比较参考?我知道如何按对象类型进行比较,但如果它们引用完全相同的对象则不知道。还是 if 语句是我唯一的选择?

【问题讨论】:

  • 这似乎是一个设计问题。这是你的真实代码吗?
  • 看起来你可以像if(A == obj || B == obj || C == obj)那样做一个if
  • 这不是我的真实代码,因为我的实际代码大约有 300 行,没有上下文就更难理解我的目标是什么,它做了很多事情,所以我做了一个简化的例子。但是我确实有很多 if 语句检查对象是否是属于结构的对象之一。我认为 case 语句会更容易编写和更优化。
  • 使用集合的解决方案可能更好。
  • 整个“栈堆”“不想使用集合”的逻辑可能有缺陷。

标签: c#


【解决方案1】:

虽然我同意评论者的观点,即您可能遇到设计问题,但您可以使用 when 过滤器和 switch

public bool Distance(object obj, out float distance)
{
    switch (obj)
    {
        case var _ when ReferenceEquals(obj, A):
            distance = DistanceFrom(A);
            return true;
        case var _ when ReferenceEquals(obj, B):
            distance = DistanceFrom(B);
            return true;
        case var _ when ReferenceEquals(obj, C):
            distance = DistanceFrom(C);
            return true;
        default:
            distance = float.PositiveInfinity;
            return false;
    }
}

我知道它看起来有点奇怪,但是 var _ 是一个丢弃,并表示您不关心 obj 的值(至少在 case 本身中,但您仍然可以使用 @987654327 @在when中。

您说您想比较参考资料。这就是ReferenceEquals 所做的。如果你不想这样,你可以使用== 或任何你认为平等的意思。

【讨论】:

    【解决方案2】:

    我建议避免使用switch,直接编写这种代码。

    试试这个:

    public bool Distance(object obj, out float distance)
    {
        MyObject[] variables = new [] { A, B, C };
        MyObject match = variables.Where(x => ReferenceEquals(x, obj)).FirstOrDefault();
        bool result = match != null;
        distance = result ? DistanceFrom(match) : float.PositiveInfinity;
        return result;
    }
    

    或者更灵活一点:

    public float? Distance(object obj)
    {
        MyObject[] variables = new [] { A, B, C };
        MyObject match = variables.Where(x => ReferenceEquals(x, obj)).FirstOrDefault();
        return match != null ? (float?)DistanceFrom(match) : null;
    }
    

    【讨论】:

    • 您使用的是Array,而 OP 说性能低...
    • “性能低”是什么意思?这与使用数组有什么关系?
    • 请看问题下方的cmets。
    • @LeiYang - 但没有证据表明这是一个问题。也可以将数组移动到一个字段,从而与单个字段处于相同的性能水平。这是一个有争议的问题。
    【解决方案3】:

    我认为您需要阅读official docs,这是使用带有when 子句的switch case 的示例:

    public struct Test
    {
       // MyObject is a class
       public MyObject A;
       public MyObject B;
       public MyObject C;
    
       public bool Distance(MyObject obj, out float distance){
            distance = float.PositiveInfinity;
            switch (obj){
                case MyObject o when  Object.ReferenceEquals(o,A):
                  distance = DistanceFrom(A);
                  return true;
                case MyObject o when  Object.ReferenceEquals(o,B):
                  distance = DistanceFrom(B);
                  return true;
                case MyObject o when  Object.ReferenceEquals(o,C):
                  distance = DistanceFrom(C);
                  return true;
                default:
                  return false;
            }
            
       }
    

    【讨论】:

    • 这如何回答这个问题?
    • 我弄错了这个例子。但在同一个文档中。
    猜你喜欢
    • 2018-03-23
    • 1970-01-01
    • 2016-08-09
    • 2014-09-08
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    相关资源
    最近更新 更多