2010-04-15 19 views
7

tengo dos interfaces IHeaderRow, y IDetailRowde fundición entre las clases que comparten la misma interfaz de

I tienen entonces un objeto que implementa tanto RawRow: IHeaderRow, IDetailRow

entonces necesito echarlo a HeaderRow que implementa IHeaderRow.

Pero cuando lo intento, termina siendo nulo o dando una excepción.

puedo emitir ObjectRawRow a cualquier interfaz IHeaderRow o IDetailRow

var ObjectIHeaderRow = ObjectRawRow as IHeaderRow; 
var ObjectIDetailRow = ObjectRawRow as IDetailRow; 

Pero no puedo emitir ObjectRawRow a HeaderRow o ObjectIHeaderRow a HeaderRow.

que arroja el error No se puede convertir tipo de fuente 'IA' para apuntar tipo 'A'

tengo que echó en la clase real HeaderRow.

¿Pensamientos?

EDIT:

A pesar de que la creación de una conversión explícita se hizo cargo de la cuestión que pensé en dar respuesta a las personas que se preguntan, por qué estaba haciendo lo que era.

En resumen, estoy procesando secuencialmente un archivo. Linea por linea. Leí la fila en RawRow, y hasta que veo algunos valores, realmente no sé qué tipo de fila va a ser. Entonces quise lanzarlo al tipo correcto.

+0

¿Qué tipo es 'ObjectRawRow' declarado? – SLaks

+0

@SLaks, ObjectRawRow es RawRow (que implementa IHeaderRow y IDetailRow) – CaffGeek

+0

una forma más agradable de hacer esto podría ser simplemente hacer que RawRow crea una instancia apropiada (actuando como * Factory *), utilizando un constructor de copia si lo desea. –

Respuesta

6

Puede sólo de forma implícita a lanzar objetos que heredan de tipos o implementan - RawRow ya no deriva de HeaderRow, no es posible.

Dependiendo de sus necesidades, usted podría superar esta escribiendo un explicit conversion operator, la creación de un constructor que acepta un HeaderRowRawRow como su prototipo, o mediante la modificación de su código para operar en una IHeaderRow.

+0

Operador de conversión funcionó de maravilla. Esto me ha preocupado muchas veces. Todo funciona muy bien como interfaces, hasta que intento serializar el objeto. Luego termino cambiando su definición de interfaces a clases ... y luego no puedo llenarlo debido a esta restricción de conversión – CaffGeek

+0

Pequeño problema de lenguaje, el OP intenta hacer un lanzamiento * explícito *, y necesita implementar un * operador de conversión implícita definido por el usuario *. –

+0

@Steven - interesante, ¿por qué dices eso? No había especificado originalmente un operador explícito, pero luego lo cambié por alguna razón, supongo que sonaba como que la conversión podría ser con pérdida o podría generar una excepción. Supongo que no está claro a partir de la pregunta, así que puedo cambiarlo a no especificado. –

1

No se puede convertir ObjectRawRow a HeaderRow a menos que uno herede de la otra.

Las interfaces no tienen nada que ver con eso.


considerar:

class Shape 
interface IHasCorners 
class Rectangle : IHasCorners, Shape 
class Triangle : IHasCorners, Shape 


Rectangle myRectangle = new Rectangle(); 
Triangle myTriangle = new Triangle(); 

//upcasts 
Shape s = (Shape)myRectangle; 
IHasCorners hc = (IHasCorners)myRectangle; 

//downcasts 
Rectangle r2 = (Rectangle)s; 
r2 = (Rectangle)hc; 

//upcasts 
s = (Shape)myTriangle; 
hc = (IHasCorners) myTriangle; 

//these downcasts won't work 
//the variables now reference a Triangle instance 
Rectangle r3 = (Rectangle)s; 
r3 = (Rectangle)hc; 
1

No podrá hacer esta conversión a menos que exista una relación de herencia entre los tipos.Si eso no es posible, lo mejor que puede hacer es crear un operador de conversión explícito que le permita convertir un tipo en otro tipo.

Si crea una conversión explícita, debe comprender que esto será más lento que la conversión, ya que invocará un método que funcionará en lugar del de conversión, que solo cambia el tipo de referencia y no cambia ninguno de los memoria en el montón.

Considere este ejemplo que no se compila:

class Example 
{ 
    static void Main() 
    { 
     Foo foo = new Foo(); 
     Bar bar = (Bar)foo; 
    } 
} 

class Foo { } 
class Bar { } 

Puesto que no hay relaciones de herencia entre los tipos ni hay una conversión explícita de Foo a Bar esto no se puede compilar.

embargo, la adición de una conversión explícita permite que se compile:

class Example 
{ 
    static void Main() 
    { 
     Foo foo = new Foo(); 
     Bar bar = (Bar)foo; 
    } 
} 

class Foo 
{ 
    public static explicit operator Bar(Foo foo) 
    { 
     return new Bar(); 
    } 
} 
class Bar { } 
+0

Gah, lo siento Andrew, he editado el tuyo en lugar del mío, y luego he devuelto el tuyo. D: –

+0

@Jeff - ¡No se preocupe! Lo he hecho muchas veces antes de mí :) –

0

Sólo se puede lanzar una instancia de una clase en particular si el objeto es en realidad una instancia de esa clase (o se deriva de la clase).

No es posible lanzar una instancia de la clase A de relación alguna clase B (que es lo que estamos tratando de hacer), incluso si implementan las mismas interfaces.

0

Puede utilizar el explicit keyword para crear métodos que serán llamados cuando intenta enviar contenido desde IA a A. La razón por la que no funciona sin que usted escriba su propio método es porque el compilador no sabe qué hacer con los valores que no se proporcionan.

+0

Los operadores de Cast son llamados en tiempo de compilación. Quizás no ayuden aquí. – SLaks

2

En primer lugar, ¿por qué tiene que hacer un reparto tan raro? Probablemente haya otro diseño para lo que estás tratando de hacer.

En segundo lugar, la razón por la que no se puede hacer el reparto es porque un RawRow no es un HeaderRow. La única garantía que tiene es que implementa IHeaderRow. El problema es que tiene un montón de otras cosas también, cosas que HeaderRow no tiene. Y viceversa - HeaderRow probablemente tiene un montón de cosas que ObjectRawRow no tiene.

Imagine que sus clases este aspecto:

interface IHeaderRow 
{ 
    string GetText(); 
} 

class HeaderRow : IHeaderRow 
{ 
    public string GetText() 
    { 
     return "My Label"; 
    } 

    public int GetFoo() 
    { 
     return 42; 
    } 
} 

class ObjectRawRow : IHeaderRow 
{ 
    public string GetText() 
    { 
     return "My Raw Label"; 
    } 
} 

Ahora bien, si usted hace esto, estás bien:

ObjectRawRow row = new ObjectRawRow(); 
IHeaderRow header = row as IHeaderRow; 
string label = header.GetText(); // fine, since GetText is guaranteed to exist 

Pero probar esto en el tamaño:

ObjectRawRow row = new ObjectRawRow(); 
HeaderRow header = row as HeaderRow; 
int magic = header.GetFoo();  // BOOM! Method doesn't exist, 
// because the object isn't really a HeaderRow under the covers. 
// It's still really an ObjectRawRow. What do you do now? Crash hard is what. 

Y es por eso que no puedes lanzar fuera del árbol de herencia.

+0

Su ejemplo no está claro: ¿puede mostrar por qué no se puede llamar a GetText en una variable de tipo HeaderRow que hace referencia a una instancia de ObjectRawRow. –

+0

No es que técnicamente no podrías, supongo, pero el compilador ni siquiera te permitirá acercarte lo suficiente como para intentarlo. Ni siquiera le permitirá lanzar un ObjectRawRow a un HeaderRow, porque entonces se está configurando para la posibilidad de bloquear el CLR. El "contrato" que es seguro llamar a cualquiera y todos los métodos de HeaderRow debe mantenerse en todo momento. – Tesserex

+0

"El compilador no": HeaderRow hr = (HeaderRow) (object) someObjectRawRow; –

4

¿Por qué necesita para su emisión a un HeaderRow en el primer lugar? Si IHeaderRow produjo la API que implementa HeaderRow, entonces solo debería poder actuar sobre los "objetos" de IHeaderRow utilizando los métodos definidos.

El punto de una interfaz es por lo que se puede tratar una agrupación de diferentes objetos como un tipo similar. No para que pueda lanzar objetos diferentes entre clases que no están vinculadas por herencia.

Cuestiones relacionadas