2013-02-22 44 views
6

Khi bạn sử dụng một con trỏ như int* trong C#, bạn cần phải sử dụng từ khóa unsafe, nhưng khi bạn sử dụng một số IntPtr, thì không. Sự khác biệt này là gì? Cả hai đều có thể trỏ đến một địa chỉ.Tại sao IntPtr không cần từ khóa không an toàn?

Bộ thu gom rác xử lý hai loại này như thế nào? Chúng có bị xử lý khác nhau không? Nếu vậy, sự khác biệt là gì? Nếu không, tại sao một người cần từ khóa unsafe?

Edit: Cảm ơn rất nhiều cho câu trả lời của mọi người cho đến nay, nhưng những gì tôi muốn biết là làm thế nào họ được xử lý khác nhau bởi các khuôn khổ và các bộ thu rác, chứ không phải là định nghĩa MSDN của IntPtr. Nó chỉ mất một tìm kiếm của Google để đến đó. Những gì tôi muốn biết tại sao IntPtr không cần từ khóa unsafe? Tôi muốn nắm bắt lý do tại sao chúng ta có thể sử dụng nó mà không có từ khóa.

Trả lời

5

Theo MSDN:

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

Nó chỉ đơn thuần là một đại diện của "một con trỏ hoặc xử lý."

tôi đã và đang làm một số đọc về cách IntPtr được xử lý khác nhau bởi GC hơn các loại quản lý khác, và tôi đã không tìm thấy bất kỳ tài liệu hoặc các sản phẩm nêu rõ IntPtr được thu thập bất kỳ khác nhau, ví dụ, ngay sau khi IntPtr đi ngoài phạm vi nó có thể là GC'd.

Về lý do tại sao không có sử dụng các từ khóa unsafe đọc câu trả lời được chấp nhận đặc biệt là cập nhật:

Does unsafe code have any effect on safe code?

unsafe đã được xác định trong việc thực hiện IntPtr (xem tờ khai trường trong việc thực hiện IntPtr bên dưới), do đó, lớp học sử dụng IntPtr không phải đánh dấu bất kỳ việc sử dụng nào là IntPtr cũng sử dụng như unsafe, nếu không sẽ bị xếp chồng lên các lớp khác có thể sử dụng các loại có mã không an toàn trong quá trình triển khai.

Bên cạnh mã unsafe không IntPtr, đó là lĩnh vực private unsafe void* m_value; đó là unsafe và bạn không sử dụng nó trực tiếp.

// 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 là một loại giá trị. Nó không phải là rác Thu thập hoặc xử lý bởi các nhà sưu tập. Nó chỉ là một số kiểu giá trị, đó là lớn như kích thước con trỏ bản địa. –

1

IntPtr là một loại được quản lý và được sử dụng, tức là để có được các tay cầm riêng của hệ điều hành Windows. Bạn không nên nhầm lẫn nó với một con trỏ thực tế như int*.

Xem MSDN để tham khảo thêm.

+0

'IntPtr' đại diện cho' void * 'và không OS-nhà cung cấp liên quan và tại sao có đến/từ phương pháp cho nó. – leppie

+0

@leppie Có, bạn đã đúng, tuy nhiên, mặc dù là 'void *' nó thường đại diện cho một số tích cực trong Windows. –

1

Một IntPtr về cơ bản chỉ là trình bày được quản lý của một loại con trỏ. Bạn có thể tự do truyền bất kỳ loại con trỏ nào đến một số IntPtr trong một ngữ cảnh không an toàn. Về cơ bản, IntPtr chỉ là một bao bọc mỏng xung quanh một void* (IIRC nó có trường riêng void*).

Nó thường trong interop với mã không được quản lý (thông qua PInvoke hoặc lớp Marshal) như là một thay thế tại chỗ với nhiều loại con trỏ không được quản lý như, giống như con trỏ, một IntPtr 's kích thước thay đổi theo kiến ​​trúc (4 byte trên một hệ thống x86, 8 trên x64).

0

Câu hỏi liên quan ... Tại sao dllimport không yêu cầu bối cảnh không an toàn?

Tôi nghi ngờ lý do IntPtr và dllimport không yêu cầu bối cảnh không an toàn là cho phép VB.NET (không có an toàn) để truy cập các API gốc một cách dễ dàng.

Tuy nhiên, chắc chắn có điều gì đó "không an toàn" về dllimport, IntPtr và tương tác của chúng.

Bàn giao đối số không hợp lệ cho điểm nhập dllimport có thể gây ra sự cố, hoặc tệ hơn, bộ nhớ bị hỏng âm thầm. Điều này có nghĩa là bất kỳ mã nào thực hiện một dllimport là trong tâm trí của tôi "không an toàn". Hơn nữa, nếu mã đó rò rỉ một IntPtr từ mã an toàn vào điểm nhập dllimport, nó cơ bản bị rò rỉ nó "không an toàn" vào mã an toàn đó, bởi vì mã an toàn có thể sửa đổi IntPtr để làm cho nó không hợp lệ.

Khi tôi sử dụng dllimport, tôi thích nhập con trỏ dưới dạng con trỏ không an toàn hơn là IntPtr. Điều này có hai lợi ích lớn. Đầu tiên, nó cho phép tôi kiểm tra kiểu cho các kiểu con trỏ khác nhau. Thứ hai, nó ngăn chặn các con trỏ nguyên gốc không được quản lý khỏi bị rò rỉ thành mã "an toàn".

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

Các vấn đề liên quan