[英]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?如果我在 C# 中声明一个接口,有什么方法可以显式声明实现该接口的任何类型都是引用类型?
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 SomeClass.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
).由于SomeClass.AnotherRoutine()
的参数必须是引用类型,因此在这里我会在调用该方法时出现编译器错误,这表明我强制T
成为引用类型( where T: IInterface, class
在声明中使用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.因此,结构或 class 是否实现接口并不重要。 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:对于合同 X:
- Throw a compile error if a struct implements/inherits X.如果结构实现/继承 X,则引发编译错误。
- X may not be an abstract class. X 可能不是抽象的 class。
Well, you're simply stuck then, because those contradict each other.好吧,你只是被卡住了,因为它们相互矛盾。
Using the constraint where T: class, IFoo
wouldn't even work all the time.使用where T: class, IFoo
甚至不会一直工作。 If I had this method (based on the same Foo
and IFoo
above):如果我有这种方法(基于上面相同的Foo
和IFoo
):
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.因此,就我而言,使用where T: class, IFoo
样式约束,然后结构是否实现接口可能无关紧要,只要它被装箱即可。 Depends on what checking EF does if passed a boxed struct, though.不过,取决于如果通过盒装结构检查 EF 会做什么。 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.如果它不起作用,至少通用约束可以让您部分实现,您可以检查foo.GetType().IsValueType
(参考我上面的DoSomething
方法)并抛出ArgumentException
来处理盒装结构的情况。
http://msdn.microsoft.com/en-us/library/d5x73970.aspx . http://msdn.microsoft.com/en-us/library/d5x73970.aspx 。 Looks like you can specify it's a "class", which means reference type.看起来你可以指定它是一个“类”,这意味着引用类型。
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 (eg 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).在许多情况下,使用不可变结构包装 class object 可能很有用(例如,实现支持多种枚举方式的 Dictionary 之类的一种方法是使 Dictionary.Keys 和 Dictionary.Values 都为结构,每个都包含对 Dictionary 的引用,并且每个都提供特殊的 GetEnumerator 方法; Dictionary 没有以这种方式实现,但它不是一个糟糕的模式)。 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);在直接调用 object 上的 GetEnumerator 的情况下,这种模式可以避免装箱(因为 vb.net 和 c# 都使用它们的鸭式 foreach 循环); because the structures are immutable, even when boxing does occur it's a performance issue rather than a correctness one.因为结构是不可变的,即使发生装箱也是性能问题而不是正确性问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.