0

I have the following class structure:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;

namespace contractsTest
{
    class Program
    {
        static void Main(string[] args)
        {
            IService s = new Service();
            s.sendMessage(MessagesCreator.TestMessage);
        }
    }

    class Service : IService
    {
        public void DoSomething(Message m)
        {
        }
    }

    static class MessageNames
    {
        public static string TestMessage
        {
            get
            {
                Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result<string>()));
                return "TestMessage";
            }
        }
    }

    class Message
    {
        public Message(string _name)
        {
            Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
            Contract.Ensures(this.Name == _name);
            this.Name = _name;
        }

        public string Name { get; private set; }
    }

    static class MessagesCreator
    {
        public static Message TestMessage
        {
            get
            {
                Contract.Ensures(Contract.Result<Message>() != null);
                Contract.Ensures(Contract.Result<Message>().Name == MessageNames.TestMessage);

                return new Message(MessageNames.TestMessage);
            }
        }
    }

    static class Extensions
    {
        public static void sendMessage(this IService service, Message m)
        {
            Contract.Requires<ArgumentNullException>(service != null);
            Contract.Requires<ArgumentNullException>(m != null);
            Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(m.Name));

            service.DoSomething(m);
        }
    }

    [ContractClass(typeof(IServiceContract))]
    interface IService
    {
        void DoSomething(Message m);
    }
    [ContractClassFor(typeof(IService))]
    abstract class IServiceContract : IService
    {
        public void DoSomething(Message m)
        {
            Contract.Requires<ArgumentNullException>(m != null);
            Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(m.Name));
            // Do Something           
        }
    }
}

In Main i get the following Warning CodeContracts: requires unproven: !string.IsNullOrWhiteSpace(m.Name)

Any idea how to fix it?

If I change main to:

static void Main(string[] args)
{
    IService s = new Service();

    Message messagesCreatorTestMessage = MessagesCreator.TestMessage;

    if (string.IsNullOrWhiteSpace(messagesCreatorTestMessage.Name))
        throw new InvalidOperationException();

    s.sendMessage(messagesCreatorTestMessage);
}

the warning disappears, but there should be other more elegant ways of doing this.

Bogdan Maxim
  • 5,866
  • 3
  • 23
  • 34

2 Answers2

3

The Ensures in the Message constructor only specifies that the condition will be true when the constructor finishes; it does not indicate that the condition will be true for the life of the Message instance.

To do this, use the Contract.Invariant method:

class Message
{
    [ContractInvariantMethod]
    private void MessageInvariants()
    {
        Contract.Invariant(!string.IsNullOrWhiteSpace(Name));
    }

    public Message(string _name)
    {
        Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
        Contract.Ensures(this.Name == _name);
        this.Name = _name;
    }

    public string Name { get; private set; }
}
Jeff Ogata
  • 56,645
  • 19
  • 114
  • 127
1

It's possible that this is the problem:

// In the Message constructor
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_componentName));

I suspect you mean:

Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));

It's not clear to me where _componentName even comes from...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Bogdan: If you were typing out your code, then it's clearly not the same code which actually gave you the error. It's also incomplete - there's no Service class, for example. Please give a short but complete program which demonstrates the problem. – Jon Skeet Nov 17 '10 at 10:06