If you pass something in the interface, then even if you have a value type that implements this interface, it will become a box if applied to the interface and behaves like a reference type (because it is placed inside the reference type).
interface IFoo { int Value { get; set; } } struct Foo : IFoo { public int Value { get; set; } }
Observe effects when using a value type:
var a = new Foo() { Value = 3 }; var b = a;
Now let's see what happens when you add it to the interface:
var a = new Foo() { Value = 3 } as IFoo;
Thus, it does not matter if the structure or class implements the interface. If it is passed to the interface and then passed through the interface, it will behave like a reference type.
Edit : If these are your requirements ...
For contract X:
- Throw a compilation error if struct implements / inherits X.
- X cannot be an abstract class.
Well, you just got stuck then because they contradict each other.
- The only way to get a compilation error if the structure implements / inherits the contract is an abstract class.
- Since you cannot use an abstract class to preserve open inheritance options, you need to use an interface.
- The only ways to enforce the rule that the structure cannot implement the interface will be performed at run time.
Using the where T: class, IFoo will not work all the time. If I had this method (based on the same Foo and IFoo above):
static void DoSomething<T>(T foo) where T: class, IFoo { foo.Value += 1; Console.WriteLine( "foo has {0}", foo.Value ); }
Then in this case a compilation error will be selected:
var a = new Foo(){ Value = 3 }; DoSomething(a);
But in this case it will be very good:
var a = new Foo(){ Value = 3} as IFoo;
So, as far as I can tell, use the where T: class, IFoo constraint, and then it may not matter if the structure implements the interface if it is boxed. Depending on what check the EF does if the boxed structure is transferred. Maybe it will work.
If that doesn't work, at least the general constraint gives you part of the path and you can check foo.GetType().IsValueType (referring to my DoSomething method above) and throw an ArgumentException to handle the case of nested structures.