views:

424

answers:

4

Given the following two interfaces (these are small examples, not my actual implementation):

public interface IAssertion<T> {
     IAssertion<T> IsNotNull();
     IAssertion<T> Evaluate(Predicate<T> predicate)
}

public interface IStringAssertion : IAssertion<string> {
     IStringAssertion IsNotNullOrEmpty();
}

and a static factory that will return the appropriate interface, for example:

public static class Require {
     public static IAssertion<T> That<T>(T value) {
          ...
     }

     public static IStringAssertion That(string value) {
          ...
     }
}

I should be able to do the following:

public void TestMethod(SomeClass a, string b) {
    Require.That(a).IsNotNull();
    Require.That(b).IsNotNullOrEmpty().Evaluate(SomeMethodThatAcceptsString);
}

This code compiles and will actually run. I can even set up tests that pass, such as:

Assert.IsInstanceOf<IStringAssertion>(Require.That(string.Empty));
Assert.IsNotInstanceOf<IStringAssertion>(Require.That(new object());

The problem I am running into and the whole point of this question, is that Visual Studio 2005 intellisense is not resolving the differences between the two.

When I type Require.That("..."). I should expect to see a list of

Evaluate(Predicate predicate)
IsNull()
IsNotNullOrEmpty()

but instead I see nothing.

I would really like to keep the same method name for the overloads. I want to keep the generic overload because of the predicate in the Evaluate method of the IAssertion interface.

Also, I know I can do something close to this using extension methods, but that is not an option because I still want to support .Net 2.0 and would like to keep the fluent api.

Updated:

There have been some good answers that involve third party add-ons to Visual Studio. Unfortunately I am not in a position to either install or purchase add-on tools for Visual Studio due to the corporate red tape that I am developing under. (I hate politics!)

I am looking for a code only option that will work in both Visual Studio 2005 and Visual Studio 2008.

Updated:

This works in Visual Studio 2008. Thank you, Luke. That only leaves Visual Studio 2005.

A: 

I believe that you have just come face to face with the reality that sometimes Intellisense is just plain not so intelligent, and is, from time to time, just stupid.

Muad'Dib
Agreed, but this code isn't just for me. It is part of some framework code that am developing for the other developers on my team and without Intellisense telling them what methods they can use, they will be lost. I don't want them to have to look it up in the documentation everytime they use these classes.
Jason
A: 

You should install Resharper then. It's a whole lot better than VS 2008 intellisense.

Ngu Soon Hui
Thanks for the response, but this really isn't an option since the company won't pay for it.
Jason
A: 

Same problem here - Intellisense is not that great.

I started using Visual Assist X, and switched to Visual Assist X.

edit: (saw your answer to the resharper suggestion) I think resharper has a free version. In any case, VAX is really worth it for you to buy it for yourself.

Fox
Resharper does have a free version for academic or open source use, neither of which I qualify for. I do have Resharper at home, and love it, but this is for use in a corporate environment by developers that don't have and won't get Resharper.
Jason
+1  A: 

I believe this is because Intellisense sees the item with the same name as a Generic Type and then doesn't bother to look for the intellisense properties until you give it a type. For example, if you mouse over the "Require.That(string)" Visual Studios will report it as an IAssertion, instead of an IStringAssertion.

Anyway, you could just rename the "That" for your IStringAssertion to "ThatString". I.e.

public static class Require
{

    public static IStringAssertion ThatString(string value)
    {
        return null;
    }

    public static IAssertion<T> That<T>(T value)
    {
        return null;
    }

}

public class RAR
{
    public void TestMethod(StringComparer a, string b)
    {
        Require.That<StringComparer>(a).IsNotNull();
        Require.ThatString(b).IsNotNullOrEmpty();
    }
}

Probably not ideal, but I don't believe there's any way around it on the code front apart from using different method names.

GenericTypeTea
That's what I was afraid of. Different method names are an option, but framework design guidelines say you should keep type names out of method names. Do you think different method names would add to the complexity of the api from a user standpoint? Keep in mind this is intended for the other developers in my corporate environment.
Jason
Well, don't take my word as gospel. There may be a way around it, but I can't see it. Ref complexity, I think it entirely depends on how many of these you intend to create. If it's just 1 or 2 for string and int, i.e. ThatString and ThatInt, then I don't see a major issue. If you're going to be using lots of types, then you may as well do away with the generic and do them all manually. I'd always stick to your coding guidelines where possible.
GenericTypeTea
This looks like it is going to be the best option. I'm going to add ThatString, ThatDate, ThatComparable... methods to the factory. Not ideal, but it will work.
Jason
It's a shame there's no alternative available. I wouldn't take offense if you unaccepted this answer and set a bounty on the question. I'm keen to see if there is another answer.
GenericTypeTea