C#函数参考:重载方法的引用

3
我是一个能够翻译文本的助手。

我有一个静态类,其中有一些重载方法。我想知道是否有一种简单/优雅的方式将对正确重载方法的引用传递给我的另一个方法。

ObjectComparer.cs:

internal static class ObjectComparer {
    internal static void AssertAreEqual(Company expected, Company actual) {
        // ...
    }

    internal static void AssertAreEqual(Contact expected, Contact actual) {
        // ...
    }
}

CollectionComparer.cs:

internal static class CollectionComparer {
    internal static void AssertAreEqual<T>(List<T> expected, List<T> actual, Action<T, T> comparer) 
    {
        Assert.AreEqual(expected.Count, actual.Count);

        for (var i = 0; i < expected.Count; i++) 
        {
            comparer(expected[i], actual[i]);
        }
    }
}

CompanyRepositoryUnitTest.cs:

[TestMethod]
public void GetAllCompaniesTest()
{
    // some work that creates 2 collections: expectedCompanies and actualCompanies

    // I am hoping I can write the following method 
    // but I am getting an error over here saying 
    // The best overloaded method ... has invalid arguments
    CollectionComparer.AssertAreEqual(expectedCompanies, actualCompanies, ObjectComparer.AssertAreEqual);
}

编辑

事实证明,编译器抱怨我其他的参数:actualCompanies。它是 ICollection 而不是 List。

很抱歉,这是一个非常愚蠢的错误。


1
你尝试过显式调用方法的类型了吗?CollectionComparer.AssertAreEqual<Company>(expectedCompanies, actualCompanies, ObjectComparer.AssertAreEqual);虽然我认为你不应该这样做,但还是值得一试。 - maraaaaaaaa
我按照上面代码示例所示进行了操作。结果发现导致问题的不是 ObjectComparer.AssertAreEqual,而是我的其他参数之一,它是 ICollection<UserInvitation> 而不是 List<UserInvitation>。 - Parth Shah
2个回答

1

当您将AssertAreEqual参数传递时,您可能希望实例化Action如下:

var action=  new Action<Company,Company>(ObjectComparer.AssertAreEqual);
CollectionComparer.AssertAreEqual(expectedCompanies, actualCompanies, action); 

对于“联系方式”,你可以简单地这样做:
var action=  new Action<Contact,Contact>(ObjectComparer.AssertAreEqual);

谢谢更新。我想知道为什么我不能直接说ObjectComparer.AssertAreEqual?出了什么问题? - Parth Shah
2
我认为他不应该实例化Action。 - maraaaaaaaa
当您执行 ObjectComparer.AssertAreEqual 时,您只是尝试“调用”函数(如果没有括号和参数,则语法上不正确)。但是,当您将其传递到 Action 委托中时,它将 method 作为参数而无需显式声明自定义委托。封装的方法必须对应于由此委托定义的方法签名。有关更多详细信息,请参见此链接 - ANewGuyInTown
ObjectComparer.AssertAreEqual不会调用函数,因为它没有括号。这是一种在C#中经常使用的传递函数引用的语法正确的方式,即省略括号的方式来表达函数。 - maraaaaaaaa
在这种情况下,它就像调用function一样(仅作说明),我知道它也被用作传递引用的一种方式。如果您查看我的答案,我已经做了同样的事情,我将ObjectComparer.AssertAreEqual作为参数传递给Action实例。因此,传递的参数封装了与委托定义的方法签名相对应的方法。 - ANewGuyInTown

1

我认为这也会有所帮助,如果你的比较器是静态的并且永远不会改变,你可能不需要每次都传递它。

internal static class CollectionComparer {
internal static void AssertAreEqual<T>(List<T> expected, List<T> actual) 
    {
        Assert.AreEqual(expected.Count, actual.Count);

        for (var i = 0; i < expected.Count; i++) 
        {
            CollectionComparer.AssertAreEqual(expected[i], actual[i]);
        }
    }
}

这是我最初的代码,但是(尽管所有这些都在我的测试代码中)我觉得它违反了单一职责原则。ObjectComparer比较对象的状态,而CollectionComparer比较集合的状态(即元素数量和元素的相等性)。 - Parth Shah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接