views:

192

answers:

2

Using the release version of Visual Studio 2010 I think there's a difference in the "Implement Interface" expansion from VS2008

If I speicify an interface and implement it in a class as so:

public interface IRepository<T> where T : IModel
{
    T Get<T>(int id);
    void Update<T>(T item);
    int Add<T>(T item);
}    

public class MockRepository : IRepository<MockUser>
{
// ...
}

Then use the "Implement Interface" expansion and get this:

public class MockRepository : IRepository<MockUser>
{
    public T Get<T>(int id)
    {
        throw new NotImplementedException();
    }

    public void Update<T>(T item)
    {
        throw new NotImplementedException();
    }

    public int Add<T>(T item)
    {
        throw new NotImplementedException();
    }
}

Instead of what I expected

public class MockRepository : IRepository<MockUser>
{
    public MockUser Get<MockUser>(int id)
    {
        throw new NotImplementedException();
    }

    public void Update<MockUser>(MockUser item)
    {
        throw new NotImplementedException();
    }

    public int Add<MockUser>(MockUser item)
    {
        throw new NotImplementedException();
    }
}

The IDE uses the type variable name from the generic interface definition T instead of the specified concrete type MockUser. Is this a bug? Or is something new just for VS2010 / .Net 4.0?

Update: This is NOT a bug, I didn't specify the interface as I inteded, it should be defined as:

public interface IRepository<T> where T : IModel
{
    T Get(int id);
    void Update(T item);
    int Add(T item);
}    

in other words I didn't need to specify the Type parameter T at the interface and method level, but only at the interface.

+4  A: 

There's no purpose to <T> as a type parameter to the interface's methods. It's not necessary, and if you remove it, you'll get the expected behavior -- except that the result is this:

public class MockRepository : IRepository<IModel>
{
    public IModel Get(int id)
    {
        throw new NotImplementedException();
    }

    public void Update()
    {
        throw new NotImplementedException();
    }

    public int Add(IModel item)
    {
        throw new NotImplementedException();
    }
}

Generic method type parameters are distinct from interface/class type parameters -- I wouldn't expect them to be implemented using IModel in your example. (In other words, the T in IRepository<T> is not the T in Get<T>.)

Ben M
In this case, the Idea is that one class may implement many IRepository<T> for many different objects, e.g. IRepository<Foo> and IRepository<Bar>, where each implementation method may need to call distinct data methods, e.g. Get<Foo>(id) may call DB.GetFoo(id) where Get<Bar>(id) may call DB.GetBar(id) this is moslty experimental code and its late so I may be missing something... let me know if that makes sense, and thanks.
TJB
Oh duh! I see now, good catch! I only need it @ the interface level, not at the method level
TJB
Just use T in the method parameters and return values - no need to specify `<T>` for the method declarations.
Ben M
@TJB - if Get/Update/Add are suppose to be always using the same type for a given instance of repository, then you don't need to redeclare `<T>` on each method. Right now you're allowing each method to work with any type. **Edit** - okay, you've got it now!
Daniel Earwicker
+4  A: 

It's doing exactly the right thing for you.

Each of the methods of your interface has its own T parameter, which is still unspecified until the caller of the method eventually specifies it. Your interface's T is unused.

Daniel Earwicker
Good spot! I didn't notice (in the brief glance) that the methods were *also* generic. I suspect neither did the OP when writing them.
Marc Gravell
Thank you for clarifying @Daniel
TJB
+1 Too, I didn't even notice :)
leppie