tags:

views:

66

answers:

2

Consider the following code:

public class SystemManager<T> where T : ISettings
{
    public SystemManager()
    {
        T implicit1 = default(T);
        T implicit2 = default(T);
        if (implicit1 != implicit2)
        {
            // This will not compile saying the compiler cannot compare
            // using '!=' two objects of type 'T' and 'T'
        }

        ISettings explicit1 = null;
        ISettings explicit2 = null;
        if (explicit1 != explicit2)
        {
            // This will compile fine
        }
    }
}

In the above, the compiler knows that T is ISettings, so why does the comparison only work out of the scope of generics? Is this going to be one of those ".NET 4 is the answer" things?

Edit:

In answer to Manu's question, why use generics as opposed to ISettings directly.

Suppose the following:

void Main()
{
    SystemManager<XmlSettings> manager = new SystemManager<XmlSettings>();
    // I want to disallow the following
    SystemManager<RegistrySettings> manager = new SystemManager<RegistrySettings>();
}

public interface ISettings
{

}

public class XmlSettings : ISettings, IDisposable
{
    public void Dispose() {  }
}

public class RegistrySettings : ISettings
{
}

This way I disallow any implementations of ISettings that do not implement IDisposable. I don't have control over ISettings and cannot make the other classes implement an ISettingsDisposable class, for example.

Disposable is one example, obviously, but you could put anything there - the idea being I may want to restrict tighter than just ISettings.

Edit 2:

In response to points about structs not being == able:

public struct StructSettings : ISettings
{

}

I could do the above and implement a generic, StructSettings version of SystemManager:

Then, in SystemManager I can compare the two structs with no runtime error.

SystemManager<StructSettings> manager = new SystemManager<StructSettings>();

This works, and the == on the structs in the constructor of SystemManager does not throw any runtime errors.

+2  A: 

Interesting: I think it has something to do with the compiler not knowing whether T is a reference or a value type, since if you add the constraint T : class- it compiles just fine.

The semantics of the comparison being that the references are compared for equality.

Vitaliy
@Vitality - see my updated answer (Edit 2). It doesn't know in the explicit version if ISettings is a ref or value type, surely?
joshcomley
I am not sure what you did.. This thing does not compile if you don't set the class constraint. I did not understand how you managed to compile it?
Vitaliy
@Vitality - I will post a link to a code file a bit later
joshcomley
+2  A: 

Apparently the operator == is not implemented in structs. That's why if you put T : class , it will work.


The link to the file so we can see the version that you say is working would be great :) . Or just edit your post.

sirrocco
But my implementation of ISettings in the explicit example could be a Struct, which is what is confusing me
joshcomley
Well then you need ISettings to implement IEquatable since there is no default == on a Struct.
sirrocco
@sirrocco - I've updated my question with a point about your answer
joshcomley
Well if you're using the second version "ISettings explicit1 = null;" - then explicit1 is a reference type and that's why it works. Just implement IEquatable use .Equals and be done with it :)
sirrocco
@sirrocco - I can get it all working obviously - compare against null and then check using .Equals (cos otherwise .Equals will obviously fail on nulls) - but I was wondering what was going on in the compiler's head! :)
joshcomley