开发者

Specify that an interface can only be implemented by reference types C#

If I declare an interface in C#, is there any way I can explicitly declare that any type implementing that interface is a reference type?

The reason I want to do this is so that wherever I use the interface as a type parameter, I don't have to specify that the implementing type also has to be a reference type.

Example of what I want to accomplish:

public interface IInterface
{
    void A();
    int B { get; }
}

public class UsingType<T> where T : IInterface
{
    public void DoSomething(T input)
    {
         SomeClass.AnotherRoutine(input);
    }
}

public class SomeClass
{
    public static void AnotherRoutine<T>(T input)
        where T : class
    {
        // Do whatever...
    }
}

As the argument to SomeClas开发者_开发问答s.AnotherRoutine() is required to be a reference type, I will here get a compiler error where I call the method, suggesting that I force T to be a reference type (where T : IInterface, class in the declaration of UsingType). Is there any way I can enforce this already at the interface level?

public interface IInterface : class

doesn't work (obviously) but maybe there's another way to accomplish the same thing?


If you are passing something around under an interface, then even if you have a value type implementing that interface it will become boxed if cast to the interface and behave like a reference type (because it is boxed inside a reference type).

interface IFoo {
    int Value { get; set; }
}

struct Foo : IFoo {
    public int Value { get; set; }
}

Observe the effects when used as a value type:

var a = new Foo() { Value = 3 };
var b = a; // copies value
b.Value = 4;
Console.WriteLine( "a has {0}", a.Value ); //output: a has 3
Console.WriteLine( "b has {0}", b.Value ); //output: b has 4

Now look what happens when you cast it to the interface:

var a = new Foo() { Value = 3 } as IFoo; //boxed
var b = a; // copies reference
b.Value = 4;
Console.WriteLine( "a has {0}", a.Value ); //output: a has 4
Console.WriteLine( "b has {0}", b.Value ); //output: b has 4

So it doesn't matter whether a struct or class implements the interface. If cast to the interface and then is passed around under the interface, then it will behave as a reference type.

Edit: So if these are your requirements...

For contract X:

  1. Throw a compile error if a struct implements/inherits X.
  2. X may not be an abstract class.

Well, you're simply stuck then, because those contradict each other.

  • The only way to get a compile error if the struct implements/inherits the contract is if it is an abstract class.
  • Since you can't use an abstract class in order to keep inheritance options open, you have to use an interface.
  • The only ways to enforce the rule that a struct cannot implement the interface will be during run-time.

Using the constraint where T: class, IFoo wouldn't even 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 it would throw a compile error under this circumstance:

var a = new Foo(){ Value = 3 };
DoSomething(a);

But it would work just fine under this circumstance:

var a = new Foo(){ Value = 3} as IFoo; //boxed
DoSomething(a);

So as far as I'm concerned, use where T: class, IFoo-style constraint, and then it may not matter if a struct implements the interface as long as it is boxed. Depends on what checking EF does if passed a boxed struct, though. Maybe it will work.

If it doesn't work, at least the generic constraint gets you part-way there, and you can check foo.GetType().IsValueType (referring to my DoSomething method above) and throw an ArgumentException to handle the case of boxed structs.


http://msdn.microsoft.com/en-us/library/d5x73970.aspx. Looks like you can specify it's a "class", which means reference type.


i dont think you can restrict interfaces in that way unfortunatly. According to msdn interfaces can be implemented by any type, both structs and classes :/


The boxing behavior of mutable structs cast as interfaces can certainly be annoying. I don't know that a prohibition on all structs would be necessary, though. There are a number of cases where it may be useful to have an immutable struct wrapping a class object (e.g. one way of implementing something like a Dictionary which supports multiple ways of enumeration would have been to have Dictionary.Keys and Dictionary.Values both be structures, each holding a reference to a Dictionary, and each providing a special GetEnumerator method; Dictionary isn't implemented that way, but it's not a bad pattern). Such a pattern may avoid boxing in cases where one calls GetEnumerator on the object directly (as vb.net and c# both do with their duck-typed foreach loops); because the structures are immutable, even when boxing does occur it's a performance issue rather than a correctness one.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜