【问题标题】:syntactic sugar for checking equality with multiple value用于检查具有多个值的相等性的语法糖
【发布时间】:2015-11-16 18:03:52
【问题描述】:

我想compare 2 equations,让我们说2*2 and 2+2 一个答案,4,使用 Visual Studio 2015,例如

if (4 == (2*2 && 2+2)) {...}

但它返回错误,“运算符'&&'不能应用于'int'和'int'类型的操作数”。我能想到的编写代码的唯一其他方法是:

if (4 == 2*2 && 4 == 2+2) {...}

这会起作用,但是当要比较很多值时会变得非常重复。有没有更简单的方法来实现这一点?

【问题讨论】:

  • 不,没有。为什么?你的用例是什么?
  • 简短回答:不。长答案:有一些方法可以用性能来换取一些语法糖,但这真的不值得。
  • 对您的“大量值”进行比较有一个更具描述性的上下文,您能否展示更多比较样本?有多少值被比较,与什么……固定值,其他变量相比?
  • 你在比较(值)类型; Object.Equals(int, int) 可能工作.. 但你可以只做匿名对象类型检查Object.Equals(new { value = 2*2 }, new { value = 2+2 })

标签: c# .net equality


【解决方案1】:
var results = new[]{ 2 + 2, 2 * 2, ... };
if (results.All(r => r == 4)) {
    ...
}

这会收集集合results 中所有操作的结果,并使用扩展方法All 来验证指定谓词是否适用于所有值;允许只写一次谓词。

【讨论】:

  • 请解释为什么这会解决 OP 的问题。帮助他人理解。
【解决方案2】:

你可以写一个函数:

public static bool AllEqual<T>(T expectedResult, params T[] calculations)
    where T : IEquatable<T>
{
    return calculations.All(x => x.Equals(expectedResult));
}

例如:

if (AllEqual(4, 2 + 2, 2 * 2, 1 + 1 + 1 + 1)) {
    // true
}

if (AllEqual(4, 2 + 2, 2 * 3)) {
    // not true
}

这甚至适用于其他类型,例如

if (AllEqual("foo", "f" + "o" + "o", "fooo".Substring(0, 3))) {
    // true
}

【讨论】:

  • 我很抱歉,我的意思是在我确认某些事情之前取消我的投票:即 int (结构值类型)是否实现 IEquatable.. 我认为它没有......
  • It does. 我的示例都编译并正常工作:)
  • 我不明白你为什么将expectedResult 设为一个单独的参数,如果它与calculations 中的任何值没有任何区别。对我来说,将它写成public static bool AllEqual&lt;T&gt;(params T[] calculations) { return calculations.Distinct().Count() == 1; } 似乎更简单(如果您想继续使用 LINQ 辅助函数)。但无论哪种方式,这仍然是一个不错的答案。
  • @BrettCaswell 结果没有区别,但如果你想把它们当作概念上的不同,那也很公平,但是AllEqual 不是一个好名字:AllEqual(a, b, c) 并没有指明哪个其中是预期值。
  • @hvd 意思是“都等于expectedResult...”。无论如何,是的,它可能具有相同的结果,但解决方案之间仍然存在语义差异。但我从未声称我的解决方案将是唯一的可能性,或者最好的,或者其他什么。而且这个问题相当模糊,我不明白你为什么要争论这个:)
【解决方案3】:

如果你想减少重复,Linq 查询效果很好:

IEnumerable<int> fourExpressions = new List<int>{ 2 + 2, 2 * 2, ... };
bool allEqualToFour = fourExpressions.All(x => x == 4);
if (allEqualToFour) { ... }

或者一行

if (new int[]{ 2 + 2, 2 * 2 }.All(x => x == 4)) { ... }

或 (ab) 使用扩展方法以获得最大的简洁性。 (一般来说,用这样的辅助方法污染所有对象并不是最好的主意,所以这个方法可以保留为静态方法。)

public static class QuestionableExtensions
{
    public static bool EqualsAllOf<T>(this T value, params T[] collection) where T : IEquatable<T>
    {
        return collection.All(t => value.Equals(t));
    }
}

public class MyClass 
{
    public void MyMethod()
    {
        if (4.EqualsAllOf(2 * 2, 2 + 2)) { ... }
    }
}

以下page 有一个很好的链接集合,用于解释 Linq 查询。

【讨论】:

  • hmm...IEnumerable&lt;T&gt; 不是LinqAll 不是Linq 表达式.. 这里根本没有Linq.. 你可以在.NET 2.0
  • @BrettCaswell AllSystem.Linq 中定义的扩展方法。我同意这不使用Linq 查询语法,但这只是(在这种情况下)System.Linq 方法的语法糖。
【解决方案4】:

你可以使用这个扩展方法

public static bool SameAs<T>(this T val, params T[] values) where T : struct
{
    return values.All(x => x.Equals(val));
}

if (4.SameAs(2*2,2+2)) { ... }

【讨论】:

    【解决方案5】:

    参考@walpen 的回答,指出AllLinq 扩展(在System.Linq.Enumerable 中定义)。

    我想提供All 的 .NET 2.0 实现,作为扩展。

    首先,我们将定义一个名为ExtensionAttributeAttribute。 (所以参考:Using extension methods in .NET 2.0?

    namespace System.Runtime.CompilerServices
    {
        [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
             | AttributeTargets.Method)]
        public sealed class ExtensionAttribute : Attribute { }
    }
    

    然后,(通过魔术)我们可以使用this 引用进行扩展。因此,我们将创建一个static class 以供ExtensionAttribute 使用:我选择通过在System.Collections.Generic 命名空间中定义一个名为Enumerablestatic class 来实现。

    namespace System.Collections.Generic
    {
        public static class Enumerable
        {
            //[System.Runtime.CompilerServices.Extension()]
            public static bool All<T>(this IEnumerable<T> list, T expectedAnswer)
                where T : IEquatable<T>, IComparable<T>
            {
                bool result = true;    
                IEnumerator<T> enumerator = list.GetEnumerator();
    
                while (enumerator.MoveNext())
                {
                    result = result && (Object.Equals(enumerator.Current, expectedAnswer));
    
                    if (!result)
                        return result;
                }
                return result;
            }
    
            public delegate bool MyFunc<T>(T next);
    
    
            public static bool All<T>(this IEnumerable<T> list, MyFunc<T> fn)
                where T : IEquatable<T>, IComparable<T>
            {
                bool result = true;    
                IEnumerator<T> enumerator = list.GetEnumerator();
    
                while (enumerator.MoveNext())
                {
                    result = result && fn.Invoke(enumerator.Current);
    
                    if (!result)
                        return result;
                }
                return result;
            }
        }
    }
    

    那么,使用它就很简单了。

    IEnumerable<int> ints = new int[] { 2 + 2, 2 * 2, 1 * 3 + 1 };
    Console.Write("Result := {0}", ints.All(4)); // outputs "Result := true"
    Console.Write("Result := {0}", ints.All(t => t.Equals(4))); // outputs "Result := true"
    

    【讨论】:

    • t =&gt; t.Equals(4) 部分有点可疑,因为我认为这是一个较新的 C# 实现。因此您有一个新的 IDE,msbuild 以较旧的框架为目标......
    【解决方案6】:

    随便乱想一下

    if (new Int32[] { 2 * 2, 2 + 2, ... }.All(t => t == 4))
    {
        MessageBox.Show("Yup");
    }
    else
    {
        MessageBox.Show("Nope");
    }
    

    对不起,我误读了我之前的代码。这将执行 OP 的逻辑。

    All 是我能找到的唯一方法。

    【讨论】:

    • 嗯..我认为这并没有真正遵循他想要做的事情的逻辑......
    • 也就是说,如果他做了new Int32[] { 2 + 2, 2 * 2, 3*3 },它仍然会包含4,对吗?
    • 仍然错误,如果两个值的测试都成功,它会显示“Yup”,但如果两个值的测试都失败,例如与new Int32[] { 3+3, 3*3 }
    • yeah.. all 几乎将是用于此逻辑的数组的唯一合适方法.. 但值得注意的是 int 确实实现了IEquatable&lt;T&gt;,(这很可能All 在它的实现中使用了什么)..
    猜你喜欢
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    相关资源
    最近更新 更多