Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use TryParse in Code Contracts without getting warning

When using Code Contracts I get the warning:

Detected call to method 'System.Int32.TryParse(System.String,System.Int32@)' without [Pure] in contracts of method

Having a class with interface and code contracts defined on the inteface like the code below. The question is how to check that the string orgNumberWithoutControlDigit can be converted to an valid integer, as it's a prereq for the modulus to work?

public string getControlDigit(string orgNumberWithoutControlDigit)
    {
        List<int> orgNumberNumbers = this.getNumberList(orgNumberWithoutControlDigit);

        List<int> productList = orgNumberNumbers.Zip(this.weightNumberList, (first, second) => first * second).ToList();

        int modular = productList.Sum() % 11;

        string controlDigit = getControlDigit(modular);

        return controlDigit;
    }

private static string getControlDigit(int modular)
    {
        string controlDigit;


        if (modular == 0)
        {
            controlDigit = "0";
        }
        else if (modular == 1)
        {
            controlDigit = "-";
        }
        else
        {
            int result = 11 - modular;
            controlDigit = result.ToString();
        }


        return controlDigit;
    }

[ContractClass(typeof(CalculateOrgNumberControlDigitBusinessContract))]
public interface ICalculateOrgNumberControlDigitBusiness
{
    string getControlDigit(string orgNumberWithoutControlDigit);
}


[ContractClassFor(typeof(ICalculateOrgNumberControlDigitBusiness))]
public abstract class CalculateOrgNumberControlDigitBusinessContract:ICalculateOrgNumberControlDigitBusiness
{
    public string getControlDigit(string orgNumberWithoutControlDigit)
    {
        Contract.Requires(orgNumberWithoutControlDigit.Length == 8);
        int parseResult;
        Contract.Requires(int.TryParse(orgNumberWithoutControlDigit, out parseResult));
        Contract.Ensures(parseResult >= 0);
        var result = Contract.Result<string>();
        Contract.Ensures(result != null && result.Length == 1);

        return default(string);
    }
}
like image 285
user1942435 Avatar asked Jul 11 '26 07:07

user1942435


2 Answers

I understand what you want to achieve, but I would say that passing orgNumberWithoutControlDigit as a string to getControlDigit [sic] is the real culprit here.

Even if you could make your contract to work - the caller must also convert the string to int in order to satisfy your contract. Now if the caller already have made that conversion to an int, why not let it pass that int instead?

I am a huge fan of Code Contracts and use it in most of my projects, and I have learned that it is not a silver bullet. So if you have to have a string parameter, remove the contract altogether and simply make sure your string is in a valid format before use.

Maybe an OrgNumberValidator helper would be a better choice than relying on contracts for this?

EDIT: Actually, I would recommend creating an OrgNumber class for handling them.

like image 162
Michael Viktor Starberg Avatar answered Jul 15 '26 21:07

Michael Viktor Starberg


You can create a pure helper method instead of calling int.TryParse directly:

[Pure]
private static bool IsInt(string s)
{
    int n;
    return int.TryParse(s, out n);
}

You could go further and wrap the TryParse in a try block, returning false if any type of exception is thrown (just to be on the safe side).

However, I tend to share Michael's opinion that you would do better by avoiding passing strings about to represent integers if you can.

like image 33
Matthew Strawbridge Avatar answered Jul 15 '26 21:07

Matthew Strawbridge



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!