Pergunta

Considere o seguinte código:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

Qual é a diferença entre os três tipos de casting (ok, o terceiro não é um casting, mas você entendeu a intenção).Qual deles deve ser preferido?

Foi útil?

Solução

string s = (string)o; // 1

Joga InvalidCastException E se o não é um string. Caso contrário, atribui o para s, ainda que o é null.

string s = o as string; // 2

Atribui null para s E se o não é um string ou se o é null. Por esse motivo, você não pode usá -lo com tipos de valor (o operador nunca poderia retornar null nesse caso). Caso contrário, atribui o para s.

string s = o.ToString(); // 3

Causa a Exceção de Referência Nula E se o é null. Atribui o que quer que seja o.ToString() volta para s, não importa que tipo o é.


Use 1 para a maioria das conversões - é simples e direto. Eu quase nunca uso 2, pois se algo não é do tipo certo, geralmente espero que ocorra uma exceção. Eu só vi uma necessidade desse tipo de funcionalidade de retorno-nulo com bibliotecas mal projetadas que usam códigos de erro (por exemplo, retornar nulo = erro, em vez de usar exceções).

3 não é um elenco e é apenas uma invocação de método. Use-o para quando precisar da representação da string de um objeto que não é de string.

Outras dicas

  1. string s = (string)o; Uso quando algo deve definitivamente ser a outra coisa.
  2. string s = o as string; Uso quando algo pode ser outros coisa.
  3. string s = o.ToString(); Use quando você não se importa com o que é, mas você só quer usar o disponível representação de seqüência de caracteres.

Realmente depende se você sabe se o é uma string e o que você quer fazer com ela. Se o seu comentário significa que o Realmente é realmente uma corda, eu preferiria a reta (string)o Elenco - é improvável que falhe.

A maior vantagem de usar o elenco reto é que, quando falha, você obtém um InvalidCastException, o que lhe diz praticamente o que deu errado.

Com o as operador, se o não é uma corda, s está configurado para null, o que é útil se você não tiver certeza e deseja testar s:

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

No entanto, se você não executar esse teste, você usará s mais tarde e ter um Exceção de Referência Nula jogado. Estes tendem a ser mais comuns e um muito Mais difícil de rastrear quando eles acontecem na natureza, pois quase todas as linhas desreferências uma variável e podem jogar uma. Por outro lado, se você está tentando lançar para um tipo de valor (qualquer primitivo, ou estruturas como Data hora), você tem que usar o elenco reto - o as não vai funcionar.

No caso especial de converter em uma string, todo objeto tem um ToString, então seu terceiro método pode estar bem se o não é nulo e você acha que o ToString o método pode fazer o que você deseja.

Se você já sabe para que tipo ele pode ser lançado, use um elenco de estilo C:

var o = (string) iKnowThisIsAString; 

Observe que somente com um elenco de estilo C você pode executar a coerção de tipo explícita.

Se você não sabe se é do tipo desejado e você vai usá -lo, se for, use Como palavra -chave:

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

Observe que Como não chamará nenhum operador de conversão de tipo. Somente não será nulo se o objeto não for nulo e nativamente do tipo especificado.

Use o ToString () para obter uma representação de string legível pelo homem de qualquer objeto, mesmo que ele não possa ser lançado para o String.

A palavra -chave AS é boa no ASP.NET quando você usa o método FindControl.

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

Isso significa que você pode operar na variável digitada, em vez de ter que então lançá -la de object Como você faria com um elenco direto:

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

Não é uma coisa enorme, mas salva linhas de código e atribuição variável, além de ser mais legível

'como' é baseado em 'é', que é uma palavra -chave que verifica em tempo de execução se o objeto for compatível com polimorficalmente (basicamente se um elenco puder ser feito) e retornará nulos se a verificação falhar.

Esses dois são equivalentes:

Usando 'como':

string s = o as string;

Usando 'é':

if(o is string) 
    s = o;
else
    s = null;

Pelo contrário, o elenco do estilo C também é feito em tempo de execução, mas lança uma exceção se o elenco não puder ser feito.

Apenas para acrescentar um fato importante:

A palavra -chave 'AS' funciona apenas com tipos de referência. Você não pode fazer:

// I swear i is an int
int number = i as int;

Nesses casos, você deve usar o elenco.

2 é útil para fundir para um tipo derivado.

Suponha uma é um animal:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

terá uma alimentado com um mínimo de elencos.

De acordo com as experiências executadas nesta página: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(Esta página está tendo alguns erros de "referenciador ilegal" aparecem às vezes, então apenas atualize se isso acontecer)

A conclusão é que o operador "As" é normalmente mais rápido que um elenco. Às vezes, muitas vezes mais rápido, às vezes apenas mais rápido.

Eu meronsonalmente "como" também é mais legível.

Portanto, como é mais rápido e "mais seguro" (não lançará exceção) e, possivelmente, mais fácil de ler, recomendo usar "como" o tempo todo.

"(String) O" resultará em uma concepção inválida, pois não há elenco direto.

"O como string" resultará em S ser uma referência nula, em vez de uma exceção sendo lançada.

"O.ToString ()" não é um elenco de qualquer tipo por se, é um método que é implementado pelo objeto e, portanto, de uma maneira ou de outra A classe é chamada e retorna uma string.

Não se esqueça que, por converter em string, também há convert.toString (algum tipo de instância do THETTYPE), onde algum tipo é um de um conjunto de tipos, essencialmente os tipos de base da estrutura.

Todas as respostas dadas são boas, se eu adicionar algo: para usar diretamente os métodos e propriedades da String (por exemplo, tolo), você não pode escrever:

(string)o.ToLower(); // won't compile

Você só pode escrever:

((string)o).ToLower();

Mas você pode escrever: em vez disso:

(o as string).ToLower();

o as A opção é mais legível (pelo menos na minha opinião).

string s = o as string; // 2

É preferido, pois evita a penalidade de desempenho da fundição dupla.

Parece que os dois são conceitualmente diferentes.

Elenco direto

Os tipos não precisam ser estritamente relacionados. Ele vem em todos os tipos de sabores.

  • Elenco implícito/explícito personalizado: Geralmente um novo objeto é criado.
  • Tipo de valor implícito: Copie sem perder informações.
  • Tipo de valor explícito: Cópia e informação podem ser perdidas.
  • IS-A Relacionamento: Alterar o tipo de referência, caso contrário, lança exceção.
  • Mesmo tipo: 'Elenco é redundante'.

Parece que o objeto será convertido em outra coisa.

Como operador

Os tipos têm um relacionamento direto. Como em:

  • Tipos de referência: É um relacionamento Os objetos são sempre os mesmos, apenas as mudanças de referência.
  • Tipos de valor: cópia de boxe e tipos anuláveis.

Parece que você vai lidar com o objeto de uma maneira diferente.

Amostras e il

    class TypeA
    {
        public int value;
    }

    class TypeB
    {
        public int number;

        public static explicit operator TypeB(TypeA v)
        {
            return new TypeB() { number = v.value };
        }
    }

    class TypeC : TypeB { }
    interface IFoo { }
    class TypeD : TypeA, IFoo { }

    void Run()
    {
        TypeA customTypeA = new TypeD() { value = 10 };
        long longValue = long.MaxValue;
        int intValue = int.MaxValue;

        // Casting 
        TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL:  call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
        IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass  ConsoleApp1.Program/IFoo

        int loseValue = (int)longValue; // explicit -- IL: conv.i4
        long dontLose = intValue; // implict -- IL: conv.i8

        // AS 
        int? wraps = intValue as int?; // nullable wrapper -- IL:  call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
        object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
        TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
        IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo

        //TypeC d = customTypeA as TypeC; // wouldn't compile
    }

Gostaria de chamar a atenção para as seguintes especificidades do como operador:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

Observe que o operador AS executa apenas conversões de referência, conversões anuláveis ​​e conversões de boxe.O operador AS não pode executar outras conversões, como conversões definidas pelo usuário, que devem ser executadas usando expressões de elenco.

Ao tentar obter a representação da string de qualquer coisa (de qualquer tipo) que possa ser potencialmente nula, prefiro a linha de código abaixo. É compacto, chama o tostring () e manipula corretamente os nulos. Se O for nulo, S conterá String.Empty.

String s = String.Concat(o);

Como ninguém mencionou, o mais próximo de Java por palavra -chave é a seguinte:

obj.GetType().IsInstanceOfType(otherObj)

Use elenco direto string s = (string) o; Se no contexto lógico do seu aplicativo string é o único tipo válido. Com essa abordagem, você vai conseguir InvalidCastException e implementar o princípio de Fail-Fast. Sua lógica estará protegida de passar mais do tipo inválido ou obter o NullReferenceException se usado as operador.

Se a lógica espera vários tipos diferentes lançados string s = o as string; e verifique null ou uso is operador.

Novo recurso legal apareceu no C# 7.0 para simplificar o elenco e o check é um Correspondência de padrões:

if(o is string s)
{
  // Use string variable s
}

or

switch (o)
{
  case int i:
     // Use int variable i
     break;
  case string s:
     // Use string variable s
     break;
 }

As duas formas a seguir de conversão de tipo (fundição) são suportadas em C#:

|

(Cv

• converter o tipo estático de V em C na expressão dada

• Somente possível se o tipo dinâmico de V for C, ou um subtipo de C

• Caso contrário, uma invalidcastException é jogada

|

v como c

• Variante não fatal de (c) V

• Assim, converta o tipo estático de V em C na expressão dada

• Retorna nulo se o tipo dinâmico de V não for C, ou um subtipo de C

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top