Si está pasando algo por debajo de una interfaz, incluso si tiene un tipo de valor implementando esa interfaz, se convertirá en un recuadro si se envía al interactuar y comportarse como un tipo de referencia (porque está encuadrado dentro de un tipo de referencia).
interface IFoo {
int Value { get; set; }
}
struct Foo : IFoo {
public int Value { get; set; }
}
observar los efectos cuando se usa como un tipo de valor:
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
Ahora mira lo que pasa cuando lanzas a la interfaz:
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
Por lo tanto, no importa si una estructura o clase implementa la interfaz. Si se lanza a la interfaz y luego se pasa por debajo de la interfaz, se comportará como un tipo de referencia.
Editar: Entonces, si estos son sus requisitos ...
Por contrato X:
- Lanzar un error de compilación si se implementa una estructura/hereda X.
- X puede no ser una clase abstracta
Bueno, simplemente estás atascado porque se contradicen entre sí.
- La única forma de obtener un error de compilación si la estructura implementa/hereda el contrato es si se trata de una clase abstracta.
- Dado que no puede usar una clase abstracta para mantener abiertas las opciones de herencia, debe usar una interfaz.
- Las únicas formas de aplicar la regla de que una estructura no puede implementar la interfaz serán durante el tiempo de ejecución.
El uso de la restricción where T: class, IFoo
ni siquiera funcionaba todo el tiempo. Si tuviera este método (basado en el mismo Foo
y IFoo
arriba):
static void DoSomething<T>(T foo) where T: class, IFoo {
foo.Value += 1;
Console.WriteLine("foo has {0}", foo.Value);
}
entonces sería lanzar un error de compilación en esta circunstancia:
var a = new Foo(){ Value = 3 };
DoSomething(a);
pero funcionaría muy bien en esta circunstancia :
var a = new Foo(){ Value = 3} as IFoo; //boxed
DoSomething(a);
en lo que a mí respecta, utilice where T: class, IFoo
limitación de estilo, y luego puede que no importe si un implem struct en la interfaz siempre que esté encuadrada. Depende de lo que comprueba EF si pasa una estructura en caja, sin embargo. Tal vez funcionará.
Si esto no funciona, al menos la restricción genérica le consigue vías parte allí, y puedes leer la foo.GetType().IsValueType
(en referencia a mi método DoSomething
arriba) y lanzar una ArgumentException
para manejar el caso de estructuras en caja.
Parece que el tipo sería un detalle de implementación, que es lo que la interfaz intenta abstraer en primer lugar. Soy curioso; ¿Por qué solo quieres permitir implementaciones de tipo de referencia? –
No creo que haya una manera de hacerlo, pero ¿realmente es mucho más trabajo agregar una cláusula adicional 'where' en su clase' UsingType <> '? – Cameron
@Ed: En mi caso específico, tengo una interfaz 'IEntity' que dejo que implementen todas mis entidades comerciales. Entity Framework exige que todos los tipos de entidad sean tipos de referencia, por lo que para todas las interacciones con EF esto es obligatorio. Como sé que no quiero tipos de entidad que no sean tipos de referencia, me gustaría especificar eso ya en la interfaz. –