Já vi os dois termos serem usados quase indistintamente em várias explicações online, e a maioria dos livros que consultei também não são totalmente claros sobre a distinção.
Existe uma maneira clara e simples de explicar a diferença que vocês conhecem?
Conversão de tipo (também conhecida como conversão de tipo )
Para usar um valor de um tipo em um contexto que espera outro.
Elenco de tipo não convertível (às vezes conhecido como trocadilho )
Uma mudança que não altera os bits subjacentes.
Coerção
Processo pelo qual um compilador converte automaticamente um valor de um tipo em um valor de outro tipo quando esse segundo tipo é exigido pelo contexto circundante.
Respostas:
Conversão de tipo :
Portanto, a coerção está implícita, o elenco é explícito e a conversão é qualquer um deles.
Alguns exemplos (da mesma fonte ):
Coerção (implícita):
double d; int i; if (d > i) d = i;
Elenco (explícito):
double da = 3.3; double db = 3.3; double dc = 3.4; int result = (int)da + (int)db + (int)dc; //result == 9
fonte
Os usos variam, como você observa.
Meus usos pessoais são:
Um "elenco" é o uso de um operador de elenco . Um operador de conversão instrui o compilador que (1) essa expressão não é conhecida como do tipo fornecido, mas eu prometo a você que o valor será desse tipo em tempo de execução; o compilador deve tratar a expressão como sendo do tipo dado e o tempo de execução produzirá um erro se não for, ou (2) a expressão é de um tipo totalmente diferente, mas há uma maneira bem conhecida de associar instâncias do tipo da expressão com instâncias do tipo convertido para. O compilador é instruído a gerar o código que executa a conversão. O leitor atento notará que esses são opostos, o que considero um truque interessante.
Uma "conversão" é uma operação pela qual um valor de um tipo é tratado como um valor de outro tipo - geralmente um tipo diferente, embora uma "conversão de identidade" ainda seja uma conversão, tecnicamente falando. A conversão pode ser "mudança de representação", como int para double, ou pode ser "preservação de representação" como string para objeto. As conversões podem ser "implícitas", que não exigem uma conversão, ou "explícitas", que exigem uma conversão.
Uma "coerção" é uma conversão implícita que altera a representação.
fonte
Data.Coerce.coerce :: Coercible a b => a -> b
funciona para tipos comprovadamente com a mesma representação;Unsafe.Coerce.unsafeCoerce :: a -> b
funciona para quaisquer dois tipos (e fará com que os demônios saiam do seu nariz se você usá-lo da maneira errada).Casting é o processo pelo qual você trata um tipo de objeto como outro tipo, Coercing é converter um objeto em outro.
Observe que no processo anterior não há conversão envolvida, você tem um tipo que gostaria de tratar como outro, digamos, por exemplo, você tem 3 objetos diferentes que herdam de um tipo base, e você tem um método que tomará esse tipo base, em qualquer ponto, se você conhece o tipo de filho específico, você pode CAST-lo para o que é e usar todos os métodos e propriedades específicas daquele objeto e isso não criará uma nova instância do objeto.
Por outro lado, coagir implica na criação de um novo objeto na memória do novo tipo e então o tipo original seria copiado para o novo, deixando ambos os objetos na memória (até que os coletores de lixo levem um ou ambos) .
Como exemplo, considere o seguinte código:
class baseClass {} class childClass : baseClass {} class otherClass {} public void doSomethingWithBase(baseClass item) {} public void mainMethod() { var obj1 = new baseClass(); var obj2 = new childClass(); var obj3 = new otherClass(); doSomethingWithBase(obj1); //not a problem, obj1 is already of type baseClass doSomethingWithBase(obj2); //not a problem, obj2 is implicitly casted to baseClass doSomethingWithBase(obj3); //won't compile without additional code }
baseClass
baseClass
otherClass
parabaseClass
, o que envolverá a criação de um novo objeto do tipo baseClass e preenchê-lo copiando os dados de obj3.Um bom exemplo é a classe Convert C #, em que fornece código personalizado para converter entre diferentes tipos.
fonte
Casting preserva o tipo de objetos. A coerção não.
A coerção é pegar o valor de um tipo que NÃO é compatível com a atribuição e converter em um tipo compatível com a atribuição. Aqui eu executo uma coerção porque
Int32
NÃO herda deInt64
... então NÃO é compatível com atribuição. Esta é uma coerção crescente (sem perda de dados). Uma coerção ampliada também é conhecida como conversão implícita . Uma Coerção realiza uma conversão.void Main() { System.Int32 a = 100; System.Int64 b = a; b.GetType();//The type is System.Int64. }
A conversão permite que você trate um tipo como se fosse de um tipo diferente, ao mesmo tempo que preserva o tipo .
void Main() { Derived d = new Derived(); Base bb = d; //b.N();//INVALID. Calls to the type Derived are not possible because bb is of type Base bb.GetType();//The type is Derived. bb is still of type Derived despite not being able to call members of Test } class Base { public void M() {} } class Derived: Base { public void N() {} }
Fonte: The Common Language Infrastructure Annotated Standard por James S. Miller
O que é estranho é que a documentação da Microsoft sobre Casting não se alinha com a definição da especificação ecma-335 de Casting.
... Isso soa como Coercions, Not Casting.
Por exemplo,
object o = 1; int i = (int)o;//Explicit conversions require a cast operator i.GetType();//The type has been explicitly converted to System.Int32. Object type is not preserved. This meets the definition of Coercion not casting.
Quem sabe? Talvez a Microsoft esteja verificando se alguém lê essas coisas.
fonte
Abaixo está uma postagem do seguinte artigo :
A diferença entre coerção e fundição é freqüentemente negligenciada. Eu posso ver por quê; muitas linguagens têm a mesma sintaxe (ou similar) e terminologia para ambas as operações. Alguns idiomas podem até mesmo se referir a qualquer conversão como “fundição”, mas a explicação a seguir se refere a conceitos no CTS.
Se estiver tentando atribuir um valor de algum tipo a um local de um tipo diferente, você pode gerar um valor do novo tipo que tenha um significado semelhante ao original. Isso é coerção. A coerção permite usar o novo tipo criando um novo valor que de alguma forma se parece com o original. Algumas coerções podem descartar dados (por exemplo, converter o int 0x12345678 para o short 0x5678), enquanto outras não (por exemplo, converter o int 0x00000008 para o short 0x0008 ou o longo 0x0000000000000008).
Lembre-se de que os valores podem ter vários tipos. Se a sua situação for um pouco diferente e você só quiser selecionar um tipo diferente de valor, a fundição é a ferramenta para o trabalho. A conversão simplesmente indica que você deseja operar em um tipo específico que inclui um valor.
A diferença no nível de código varia de C # a IL. Em C #, tanto o elenco quanto a coerção são bastante semelhantes:
static void ChangeTypes(int number, System.IO.Stream stream) { long longNumber = number; short shortNumber = (short)number; IDisposable disposableStream = stream; System.IO.FileStream fileStream = (System.IO.FileStream)stream; }
No nível IL, eles são bastante diferentes:
ldarg.0 conv.i8 stloc.0 ldarg.0 conv.i2 stloc.1 ldarg.1 stloc.2 ldarg.1 castclass [mscorlib]System.IO.FileStream stloc.3
Quanto ao nível lógico, existem algumas diferenças importantes. O que é mais importante lembrar é que a coerção cria um novo valor, enquanto o casting não. A identidade do valor original e do valor após a conversão são os mesmos, enquanto a identidade de um valor coagido difere do valor original; a coersão cria uma instância nova e distinta, enquanto o elenco não. Um corolário é que o resultado da fundição e o original sempre serão equivalentes (tanto em identidade quanto em igualdade), mas um valor coagido pode ou não ser igual ao original e nunca compartilhar a identidade original.
É fácil ver as implicações da coerção nos exemplos acima, pois os tipos numéricos são sempre copiados por valor. As coisas ficam um pouco mais complicadas quando você está trabalhando com tipos de referência.
class Name : Tuple<string, string> { public Name(string first, string last) : base(first, last) { } public static implicit operator string[](Name name) { return new string[] { name.Item1, name.Item2 }; } }
No exemplo abaixo, uma conversão é um elenco, enquanto a outra é uma coerção.
Tuple<string, string> tuple = name; string[] strings = name;
Após essas conversões, tupla e nome são iguais, mas strings não são iguais a nenhum deles. Você poderia tornar a situação um pouco melhor (ou um pouco mais confusa) implementando Equals () e operator == () na classe Name para comparar um Name e uma string []. Esses operadores “consertariam” o problema de comparação, mas você ainda teria duas instâncias separadas; qualquer modificação nas strings não seria refletida no nome ou tupla, enquanto as mudanças em nome ou tupla seriam refletidas no nome e na tupla, mas não nas strings.
Embora o exemplo acima tenha como objetivo ilustrar algumas diferenças entre conversão e coerção, ele também serve como um ótimo exemplo de por que você deve ser extremamente cauteloso ao usar operadores de conversão com tipos de referência em C #.
fonte
Do padrão CLI :
fonte
De acordo com a Wikipedia,
A diferença entre fundição de tipo e coerção de tipo é a seguinte:
TYPE CASTING | TYPE COERCION | 1. Explicit i.e., done by user | 1. Implicit i.e., done by the compiler | 2. Types: | 2. Type: Static (done at compile time) | Widening (conversion to higher data | type) Dynamic (done at run time) | Narrowing (conversion to lower data | type) | 3. Casting never changes the | 3. Coercion can result in representation the actual type of object | as well as type change. nor representation. |
Nota : Casting não é conversão. É apenas o processo pelo qual tratamos um tipo de objeto como outro tipo. Portanto, o tipo real de objeto, bem como a representação, não é alterado durante a fundição.
Concordo com as palavras de @PedroC88:
fonte