Lepszy sposób na rzutowanie obiektu na int


179

To prawdopodobnie trywialne, ale nie mogę wymyślić lepszego sposobu na zrobienie tego. Mam obiekt COM, który zwraca wariant, który staje się obiektem w C #. Jedyny sposób, w jaki mogę to wprowadzić do int, to

int test = int.Parse(string.Format("{0}", myobject))

Czy jest na to czystszy sposób? Dzięki

Odpowiedzi:


362

Masz kilka możliwości:

  • (int)- Operator rzutowania. Działa, jeśli obiekt jest już liczbą całkowitą na pewnym poziomie w hierarchii dziedziczenia lub jeśli zdefiniowano niejawną konwersję.

  • int.Parse()/int.TryParse() - Do konwersji z ciągu o nieznanym formacie.

  • int.ParseExact()/int.TryParseExact() - Do konwersji z ciągu znaków w określonym formacie

  • Convert.ToInt32() - Do konwersji obiektu nieznanego typu. Użyje jawnej i niejawnej konwersji lub implementacji IConvertible, jeśli taka jest zdefiniowana.

  • as int?- Zanotuj "?". asOperator jest tylko dla typów referencyjnych, a więc użyłem „?” oznaczać Nullable<int>. Operator „ as” działa tak samo Convert.To____(), jak , ale TryParse()raczej zamiast Parse(): zwraca, nulla nie rzuca wyjątek, jeśli konwersja się nie powiedzie.

Spośród nich wolałbym, aby (int)obiekt był po prostu liczbą całkowitą w pudełku. W przeciwnym razie użyj Convert.ToInt32()w tym przypadku.

Zwróć uwagę, że jest to bardzo ogólna odpowiedź: chcę zwrócić uwagę na odpowiedź Darrena Clarka, ponieważ uważam, że dobrze radzi sobie ze szczegółami tutaj, ale przyszedł późno i nie został jeszcze głosowany. Otrzymuje mój głos na „zaakceptowaną odpowiedź”, w każdym razie za zalecenie (int), za wskazanie, że jeśli to się nie powiedzie, (int)(short)może to zadziałać, i za zalecenie sprawdzenia debugera, aby dowiedzieć się, jaki jest rzeczywisty typ środowiska wykonawczego.


Znalazłem punkt, który tak naprawdę nie był błędem, ale być może zbytnio uprościł sprawę, aby ktoś mógł tak pomyśleć. Usunąłem to zdanie i dodałem link do wiarygodnej dokumentacji.
Joel Coehoorn

Czy bezpośrednia obsada będzie działać z niejawną konwersją? Miałem wrażenie, że to stricte wystarczy tylko unboxing, a nie inne konwersje.
Darren Clark

Niezupełnie odpowiedź, ale przeczytaj to: blogs.msdn.com/ericlippert/archive/2009/03/19/…
Joel Coehoorn

Skutek jest taki, że zdecydowanie robi więcej niż tylko rozpakowywanie. W przeciwnym razie, na przykład, dlaczego miałbyś go użyć do rzutowania double na int?
Joel Coehoorn

Czytając kilka innych rzeczy, mogę mieć moje ukryte / jawne wstecz - ale tak czy inaczej myślę, że to ma sens.
Joel Coehoorn

41

Obsada (int) myobject powinna po prostu działać.

Jeśli to daje nieprawidłowy wyjątek rzutowania, to prawdopodobnie dlatego, że typ wariantu nie jest VT_I4. Obstawiam, że wariant z VT_I4 jest konwertowany na int boxed, VT_I2 na short box itd.

Podczas rzutowania na opakowany typ wartości można rzutować tylko na typ w pudełku. Na przykład, jeśli zwrócony wariant jest w rzeczywistości VT_I2, to (int) (short) myObjectpowinien działać.

Najłatwiejszym sposobem, aby się tego dowiedzieć, jest zbadanie zwróconego obiektu i przyjrzenie się jego typowi w debugerze. Upewnij się również, że w zestawie międzyoperacyjnym masz wartość zwracaną oznaczoną za pomocąMarshalAs(UnmanagedType.Struct)


32

Convert.ToInt32 (myobject);

to obsłuży przypadek, w którym myobject ma wartość null i zwróci 0, zamiast zgłaszać wyjątek.


Kiedy próbuję w ten sposób, pojawia się komunikat „Nie można rozwiązać symbolu„ ToInt ””. Działa tylko wtedy, gdy używam np ToInt32.
Tobias Feil

Gdzie możemy znaleźć tę metodę? Czy jest w bibliotece .Net Framework?
Amir Pourmand امیر پورمند

8

Użyj Int32.TryParsew następujący sposób.

  int test;
  bool result = Int32.TryParse(value, out test);
  if (result)
  {
     Console.WriteLine("Sucess");         
  }
  else
  {
     if (value == null) value = ""; 
     Console.WriteLine("Failure");
  }

W rzeczywistości Parse wywołuje TryParse i zgłasza wyjątek, jeśli TryParse zwraca false. Dlatego TryParse nie obsługuje wyjątku, ponieważ nigdy go nie zgłasza.
Samuel

Cóż, technicznie rzecz biorąc, oba wywołują tę samą metodę NumberToInt32, ale tylko Parse zgłasza wyjątki, gdy nie działa.
Samuel

TryParse nadal wymaga konwersji wariantu na ciąg. Okazuje się, że problem nie polega na konwersji z ciągu znaków na liczbę int, ale z wariantu, który jest wartością typu int, na rzeczywistą wartość typu int.
Darren Clark

3

Wymieniam różnice w każdym ze sposobów rzucania. Jaki konkretny typ odlewu obsługuje, a nie?

    // object to int
    // does not handle null
    // does not handle NAN ("102art54")
    // convert value to integar
    int intObj = (int)obj;

    // handles only null or number
    int? nullableIntObj = (int?)obj; // null
    Nullable<int> nullableIntObj1 = (Nullable<int>)obj; // null

   // best way for casting from object to nullable int
   // handles null 
   // handles other datatypes gives null("sadfsdf") // result null
    int? nullableIntObj2 = obj as int?; 

    // string to int 
    // does not handle null( throws exception)
    // does not string NAN ("102art54") (throws exception)
    // converts string to int ("26236")
    // accepts string value
    int iVal3 = int.Parse("10120"); // throws exception value cannot be null;

    // handles null converts null to 0
    // does not handle NAN ("102art54") (throws exception)
    // converts obj to int ("26236")
    int val4 = Convert.ToInt32("10120"); 

    // handle null converts null to 0
    // handle NAN ("101art54") converts null to 0
    // convert string to int ("26236")
    int number;

    bool result = int.TryParse(value, out number);

    if (result)
    {
        // converted value
    }
    else
    {
        // number o/p = 0
    }


2
var intTried = Convert.ChangeType(myObject, typeof(int)) as int?;

1
Uważam, że ta odpowiedź jest naprawdę przydatna, chciałem rzucić bajt z pudełkiem na int i sprawiłem, że zadziała przy użyciu Convert.ChangeType. Powiedziałbym, że może nie być idealną odpowiedzią na OP, ale dla niektórych jest to zdecydowanie pomocne!
Philippe Paré

1

Jest też TryParse .

Z MSDN:

private static void TryToParse(string value)
   {
      int number;
      bool result = Int32.TryParse(value, out number);
      if (result)
      {
         Console.WriteLine("Converted '{0}' to {1}.", value, number);         
      }
      else
      {
         if (value == null) value = ""; 
         Console.WriteLine("Attempted conversion of '{0}' failed.", value);
      }
   }

1

Dziwne, ale przyjęta odpowiedź wydaje się błędna co do rzutowania i Convert w tym sensie, że z moich testów i czytania dokumentacji również nie powinno uwzględniać operatorów niejawnych ani jawnych.

Tak więc, jeśli mam zmienną typu object, a klasa „pudełkowa” ma zdefiniowane pewne niejawne operatory, nie będą one działać.

Zamiast tego inny prosty sposób, ale tak naprawdę wycenianie wydajności polega na rzucaniu wcześniej w trybie dynamicznym.

(int) (dynamiczny) myObject.

Możesz to wypróbować w interaktywnym oknie VS.

public class Test
{
  public static implicit operator int(Test v)
  {
    return 12;
  }
}

(int)(object)new Test() //this will fail
Convert.ToInt32((object)new Test()) //this will fail
(int)(dynamic)(object)new Test() //this will pass

1
to prawda , ale na pewno jest to coś, co chciałbyś profilować, jeśli robisz to dużo - dynamicjest daleki od
darmowości

@MarcGravell Całkowicie się z tobą zgadzam, jak również napisałem w odpowiedzi.
eTomm

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.