Comparing result from hash comparison result in "Try specifying the the type arguments explicitly"

Viewed 63

I'm trying to compare the hash output of two methods and see if they are equal.

This is my code so far:

Helper.cs:

public static bool HashIsTheSame<TResult>(Func<object[], TResult> method1, Func<object[], TResult> method2, params object[] args)
{
    TResult method1Result = method1(args);
    TResult method2Result = method2(args);

    return GetHashString(method1Result).Equals(GetHashString(method2Result));
}

private static string GetHashString(object inputString)
{
    StringBuilder sb = new StringBuilder();
    foreach (byte b in GetHash(inputString.ToString()))
        sb.Append(b.ToString("X2"));

    return sb.ToString();
}

private static byte[] GetHash(string inputString)
{
    HashAlgorithm algorithm = SHA256.Create();
    return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}

repo.cs:

public int TestMethod1(int value1, int value2)
{
    return value1 + value2;
}
public int TestMethod2(int value1, int value2)
{
   return value1 * value2;
}

When I call it like this:

Test.cs:

public void HashTest()
{
    var value1 = 1;
    var value2 = 2;
    object[] args = {value1, value2};
    Assert.IsFalse(TestHelper.HashIsTheSame(repo.TestMethod1(value1, value2), repo.TestMethod2(value1, value2), args));
}

I get the error message: "The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly." What am I doing wrong?

1 Answers

Func<object[], int> and Func<int, int, int> are incompatible. Since Func<params object[], TResult> is impossible the only way is defining multiple overloads like this:

static class TestHelper
{
    public static bool HashIsTheSame<TResult>(Func<TResult> method1,
        Func<TResult> method2) =>
        GetHashString(method1()).Equals(method2());

    public static bool HashIsTheSame<T, TResult>(Func<T, TResult> method1,
        Func<T, TResult> method2,
        T arg) =>
        GetHashString(method1(arg)).Equals(method2(arg));

    public static bool HashIsTheSame<T1, T2, TResult>(Func<T1, T2, TResult> method1,
        Func<T1, T2, TResult> method2,
        T1 arg1, T2 arg2) =>
        GetHashString(method1(arg1, arg2)).Equals(method2(arg1, arg2));

    public static bool HashIsTheSame<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> method1,
        Func<T1, T2, T3, TResult> method2,
        T1 arg1, T2 arg2, T3 arg3) =>
        GetHashString(method1(arg1, arg2, arg3)).Equals(method2(arg1, arg2, arg3));

    public static bool HashIsTheSame<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> method1,
        Func<T1, T2, T3, T4, TResult> method2,
        T1 arg1, T2 arg2, T3 arg3, T4 arg4) =>
        GetHashString(method1(arg1, arg2, arg3, arg4)).Equals(method2(arg1, arg2, arg3, arg4));

    public static bool HashIsTheSame<T1, T2, T3, T4, T5, TResult>(Func<T1, T2, T3, T4, T5, TResult> method1,
        Func<T1, T2, T3, T4, T5, TResult> method2,
        T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) =>
        GetHashString(method1(arg1, arg2, arg3, arg4, arg5)).Equals(method2(arg1, arg2, arg3, arg4, arg5));

    // etc. Depends on what number of arguments you believe to make sense.
}

With this approach it compiles:

var repo = new Repo();
Assert.IsFalse(TestHelper.HashIsTheSame(repo.TestMethod1, repo.TestMethod2, 1, 2));

Solution 2:

Your code will not compile even with explicit parameters:

Assert.IsFalse(TestHelper.HashIsTheSame(new Func<object[], int>(repo.TestMethod1), new Func<object[], int>(repo.TestMethod2), 1, 2));

No overload for 'TestMethod1' matches delegate 'Func<object[], int>'

No overload for 'TestMethod2' matches delegate 'Func<object[], int>'

If you change it to:

Assert.IsFalse(TestHelper.HashIsTheSame(new Func<int, int, int>(repo.TestMethod1), new Func<int, int, int>(repo.TestMethod2), 1, 2));

you get your original error:

The type arguments for method 'TestHelper.HashIsTheSame<TResult>(Func<object[], TResult>, Func<object[], TResult>, params object[])' cannot be inferred from the usage. Try specifying the type arguments explicitly.

But if you change your HashIsTheSame:

public static bool HashIsTheSame(MulticastDelegate method1, MulticastDelegate method2, params object[] args)
{
    object method1Result = method1.DynamicInvoke(args);
    object method2Result = method2.DynamicInvoke(args);

    return GetHashString(method1Result).Equals(method2Result);
}

the assertion compiles and works. Though it costs you performance now.

Related