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

Steve
źródło

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.

Joel Coehoorn
źródło
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)

Darren Clark
źródło
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.

Zahir J
źródło
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");
  }
Srikar Doddi
źródło
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
    }
Nayas Subramanian
źródło
2

Może Convert.ToInt32 .

W obu przypadkach uważaj na wyjątek.

JW
źródło
2
var intTried = Convert.ChangeType(myObject, typeof(int)) as int?;
Tohid
źródło
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);
      }
   }
Lance Harper
źródło
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
eTomm
źródło
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
0
int i = myObject.myField.CastTo<int>();
Nie
źródło