2013-02-22 18 views
6

Gdy używasz wskaźnika takiego jak int* w języku C#, musisz użyć słowa kluczowego unsafe, ale kiedy używasz IntPtr, nie robisz tego. Jaka jest różnica? Oboje mogą wskazać adres.Dlaczego IntPtr nie potrzebuje niebezpiecznego słowa kluczowego?

W jaki sposób odśmiecacz radzi sobie z tymi dwoma typami? Czy traktuje się je inaczej? Jeśli tak, jaka jest różnica? Jeśli nie, dlaczego potrzebne jest słowo kluczowe unsafe?

Edit: dziękuję za odpowiedzi każdego z nas do tej pory, ale to, co chciałbym wiedzieć, w jaki sposób są one traktowane inaczej przez ramy i śmieciarza, zamiast definicji MSDN IntPtr. Wystarczy jedno wyszukiwanie Google. Co chciałbym wiedzieć, dlaczego IntPtr nie potrzebuje słowa kluczowego unsafe? Chciałbym zrozumieć powód, dla którego możemy go użyć bez słowa kluczowego.

Odpowiedz

5

Zgodnie z MSDN:

http://msdn.microsoft.com/en-gb/library/system.intptr(v=vs.100).aspx

Jest jedynie reprezentacja z "wskaźnikiem lub uchwytem."

robiłem trochę lektury, w jaki sposób IntPtr jest traktowane inaczej przez GC niż innych zarządzanych typów, a nie znalazłem wszelką dokumentację lub artykuły stwierdzające IntPtr zbierane inaczej, to znaczy, jak tylko IntPtr idzie poza zakresem może być GCd.

o tym, dlaczego nie ma sensu słowa kluczowego unsafe czytać Zaakceptowanych odpowiedź zwłaszcza zmiana:

Does unsafe code have any effect on safe code?

unsafe został już określony w realizacji IntPtr (patrz deklaracje pól w realizacji IntPtr poniżej), więc klasa używająca IntPtr nie musi oznaczać żadnego użytku z IntPtr również używa jako unsafe również, w przeciwnym razie byłaby kaskadowo aż do innych klas, które mogłyby używać typów, które mają niebezpieczny kod w ich implementacji.

Oprócz kodu unsafe nie IntPtr jest, to jest pole private unsafe void* m_value; czyli unsafe i nie są bezpośrednio przy użyciu.

// Type: System.IntPtr 
// Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll 

using System.Globalization; 
using System.Runtime; 
using System.Runtime.ConstrainedExecution; 
using System.Runtime.InteropServices; 
using System.Runtime.Serialization; 
using System.Security; 

namespace System 
{ 
    [ComVisible(true)] 
    [__DynamicallyInvokable] 
    [Serializable] 
    public struct IntPtr : ISerializable 
    { 
    [SecurityCritical] 
    private unsafe void* m_value; 
    public static readonly IntPtr Zero; 

    [__DynamicallyInvokable] 
    public static int Size 
    { 
     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable] get 
     { 
     return 4; 
     } 
    } 

    [SecuritySafeCritical] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    [__DynamicallyInvokable] 
    public IntPtr(int value) 
    { 
     this.m_value = (void*) value; 
    } 

    [SecuritySafeCritical] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    [__DynamicallyInvokable] 
    public IntPtr(long value) 
    { 
     this.m_value = (void*) checked ((int) value); 
    } 

    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    [SecurityCritical] 
    [CLSCompliant(false)] 
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 
    public IntPtr(void* value) 
    { 
     this.m_value = value; 
    } 

    [SecurityCritical] 
    private IntPtr(SerializationInfo info, StreamingContext context) 
    { 
     long int64 = info.GetInt64("value"); 
     if (IntPtr.Size == 4 && (int64 > (long) int.MaxValue || int64 < (long) int.MinValue)) 
     throw new ArgumentException(Environment.GetResourceString("Serialization_InvalidPtrValue")); 
     this.m_value = (void*) int64; 
    } 

    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    public static explicit operator IntPtr(int value) 
    { 
     return new IntPtr(value); 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    public static explicit operator IntPtr(long value) 
    { 
     return new IntPtr(value); 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    [SecurityCritical] 
    [CLSCompliant(false)] 
    public static explicit operator IntPtr(void* value) 
    { 
     return new IntPtr(value); 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    [CLSCompliant(false)] 
    public static explicit operator void*(IntPtr value) 
    { 
     return value.ToPointer(); 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    public static explicit operator int(IntPtr value) 
    { 
     return (int) value.m_value; 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    public static explicit operator long(IntPtr value) 
    { 
     return (long) (int) value.m_value; 
    } 

    [SecuritySafeCritical] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    public static bool operator ==(IntPtr value1, IntPtr value2) 
    { 
     return value1.m_value == value2.m_value; 
    } 

    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    public static bool operator !=(IntPtr value1, IntPtr value2) 
    { 
     return value1.m_value != value2.m_value; 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    public static IntPtr operator +(IntPtr pointer, int offset) 
    { 
     return new IntPtr(pointer.ToInt32() + offset); 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    public static IntPtr operator -(IntPtr pointer, int offset) 
    { 
     return new IntPtr(pointer.ToInt32() - offset); 
    } 

    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [SecuritySafeCritical] 
    internal unsafe bool IsNull() 
    { 
     return (IntPtr) this.m_value == IntPtr.Zero; 
    } 

    [SecurityCritical] 
    unsafe void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     if (info == null) 
     throw new ArgumentNullException("info"); 
     info.AddValue("value", (long) (int) this.m_value); 
    } 

    [SecuritySafeCritical] 
    [__DynamicallyInvokable] 
    public override unsafe bool Equals(object obj) 
    { 
     if (obj is IntPtr) 
     return this.m_value == ((IntPtr) obj).m_value; 
     else 
     return false; 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    [__DynamicallyInvokable] 
    public override unsafe int GetHashCode() 
    { 
     return (int) this.m_value; 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [__DynamicallyInvokable] 
    public unsafe int ToInt32() 
    { 
     return (int) this.m_value; 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [SecuritySafeCritical] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [__DynamicallyInvokable] 
    public unsafe long ToInt64() 
    { 
     return (long) (int) this.m_value; 
    } 

    [SecuritySafeCritical] 
    [__DynamicallyInvokable] 
    public override unsafe string ToString() 
    { 
     return ((int) this.m_value).ToString((IFormatProvider) CultureInfo.InvariantCulture); 
    } 

    [SecuritySafeCritical] 
    [__DynamicallyInvokable] 
    public unsafe string ToString(string format) 
    { 
     return ((int) this.m_value).ToString(format, (IFormatProvider) CultureInfo.InvariantCulture); 
    } 

    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    public static IntPtr Add(IntPtr pointer, int offset) 
    { 
     return pointer + offset; 
    } 

    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
    public static IntPtr Subtract(IntPtr pointer, int offset) 
    { 
     return pointer - offset; 
    } 

    [SecuritySafeCritical] 
    [CLSCompliant(false)] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
    public unsafe void* ToPointer() 
    { 
     return this.m_value; 
    } 
    } 
} 
+0

IntPtr jest typem wartości. To nie jest Garbage Collected lub obsługiwane przez kolekcjonera. Jest to po prostu liczba typu wartości, która jest tak duża, jak rozmiar natywnego wskaźnika. –

1

IntPtr jest typem zarządzanym i jest używany, tj. Do uzyskania macierzystych uchwytów systemu operacyjnego Windows. Nie należy mylić tego z rzeczywistym wskaźnikiem, takim jak int*.

Aby uzyskać dodatkowe informacje, patrz MSDN.

+0

'IntPtr' reprezentuje' * 'void i nie OS-sprzedawca związane i dlatego nie są do/z metod niego. – leppie

+0

@leppie Tak, masz rację, ale mimo że jest "void *", zwykle oznacza liczbę dodatnią w systemie Windows. –

1

An IntPtr jest zasadniczo tylko udało reprezentacja typu wskaźnika. Możesz swobodnie rzutować dowolne typy wskaźników na IntPtr w niebezpiecznym kontekście. Zasadniczo IntPtr jest tylko cienka owijka wokół void* (IIRC zawiera prywatną void* pole).

To powszechnie podczas współdziałanie z kodem niezarządzanym (przez PInvoke lub klasy Marshal) jako zamiennik w miejscu dla niezarządzani typów wskaźnikowych AS, takich jak wskaźniki, IntPtr „s rozmiar waha się z architekturą (4 bajty na systemie x86 8 na x64).

0

Pokrewne pytanie ... Dlaczego dllimport nie wymaga niebezpiecznego kontekstu?

Podejrzewam, że powodem, dla którego IntPtr i dllimport nie wymagają niebezpiecznych warunków jest włączenie VB.NET (które nie ma niebezpieczeństwa) w celu łatwego dostępu do natywnych interfejsów API.

Jednak z pewnością istnieje coś "niebezpiecznego" w dllimport, IntPtr i ich interakcji.

Podanie nieprawidłowych argumentów do punktu wejścia dllimport może spowodować awarię lub, co gorsza, cichą awarię pamięci. Oznacza to, że każdy kod, który działa w dllimport jest "niebezpieczny". Co więcej, jeśli ten kod wycieknie IntPtr z bezpiecznego kodu do punktu wejścia dllimport, to w zasadzie wyciekł to "unsafety" do tego bezpiecznego kodu, ponieważ bezpieczny kod mógłby zmodyfikować IntPtr, aby uczynić go nieważnym.

Kiedy używam programu dllimport, wolę pisać wskaźniki niż niebezpieczne wskaźniki struktury, a nie IntPtr. Ma to dwie duże zalety. Po pierwsze, daje mi sprawdzenie typu dla różnych typów natywnych wskaźników. Po drugie, zapobiega niebezpiecznemu wyciekowi niebezpiecznych niezarządzanych natywnych wskaźników do "bezpiecznego" kodu.

http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=339290&av=638710

http://software.1713.n2.nabble.com/using-unsafe-struct-instead-of-IntPtr-with-PInvoke-td5861023.html

Powiązane problemy