指定接口只能由引用类型C#实现 [英] Specify that an interface can only be implemented by reference types C#

查看:67
本文介绍了指定接口只能由引用类型C#实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我使用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.

我要完成的示例:

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...
    }
}

由于 SomeClass.AnotherRoutine()的参数必须是引用类型,因此我在调用该方法时会遇到编译器错误,建议我强制使用 T 作为引用类型( UsingType 声明中的,其中T:IInterface,类).我有什么办法可以在接口级别上强制执行此操作?

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). 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...

对于X合同:

  1. 如果结构实现/继承了X,则会引发编译错误.
  2. X可能不是抽象类.

那么,您就被困住了,因为它们彼此矛盾.

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

  • 如果struct实现/继承协定,则获得编译错误的唯一方法是如果它是抽象类.
  • 由于不能使用抽象类来使继承选项保持打开状态,因此必须使用接口.
  • 强制执行结构无法实现接口的规则的唯一方法是在运行时.

使用约束其中T:类,IFoo 甚至不能一直工作.如果我有此方法(基于上面相同的 Foo IFoo ):

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);

就我而言,请使用 where T:class,IFoo 样式的约束,然后,只要将其装箱就可以实现结构即可.但是,如果通过盒装结构,则取决于EF进行的检查.也许会起作用.

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.

如果它不起作用,至少通用约束会使您分得一杯part,您可以检查 foo.GetType().IsValueType (请参阅我的 DoSomething 方法)并抛出一个 ArgumentException 来处理盒装结构的情况.

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.

这篇关于指定接口只能由引用类型C#实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆