C# 选择目录的包装类。

 
  1. using System;
  2.         using System.Text;
  3.         using System.Runtime.InteropServices;
  4.         public class OpenFolderDialog
  5.         {
  6.             /*
  7.             private struct SHITEMID
  8.             {
  9.              ushort cb;
  10.              byte adID; // BYTE abID[1];
  11.             }
  12.             private struct ITEMIDLIST
  13.             {
  14.              SHITEMID mkid;
  15.             }
  16.             */
  17.             [StructLayout(LayoutKind.Sequential)]
  18.             private struct BROWSEINFO
  19.             {
  20.                 public IntPtr hwndOwner; // HWND hwndOwner
  21.                 public IntPtr pidlRoot; // const ITEMIDLIST* pidlRoot
  22.                 [MarshalAs(UnmanagedType.LPTStr)]
  23.                 public string pszDisplayName;
  24.                 [MarshalAs(UnmanagedType.LPTStr)]
  25.                 public string lpszTitle;
  26.                 public int ulFlags;
  27.                 [MarshalAs(UnmanagedType.FunctionPtr)]
  28.                 public BrowseCallBackProc lpfn;
  29.                 [MarshalAs(UnmanagedType.LPTStr)]
  30.                 public string lParam;
  31.                 public int iImage;
  32.             }
  33.             [DllImport("User32.Dll")]
  34.             [return: MarshalAs(UnmanagedType.Bool)]
  35.             private extern static bool SendMessage(IntPtr hWnd, uint Msg, uint wParam, [MarshalAs(UnmanagedType.LPTStr)] string lParam);
  36.             [DllImport("Shell32.dll", CharSet = CharSet.Auto)]
  37.             private extern static IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi);
  38.             [DllImport("Shell32.dll", CharSet = CharSet.Auto)]
  39.             [return: MarshalAs(UnmanagedType.Bool)]
  40.             private extern static bool SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath);
  41.             private delegate int BrowseCallBackProc(IntPtr hwnd, uint msg, IntPtr lParam, [MarshalAs(UnmanagedType.LPTStr)] string lpData);
  42.             private static int BrowseCtrlCallback(IntPtr hwnd, uint uMsg, IntPtr lParam, [MarshalAs(UnmanagedType.LPTStr)] string lpData)
  43.             {
  44.                 if (uMsg == 1) // BFFM_INITIALIZED
  45.                 {
  46.                     string szPath = lpData;
  47.                     if (szPath != null && szPath != "")
  48.                     {
  49.                         if (szPath[szPath.Length - 1] != '//')
  50.                             szPath += '//';
  51.                         SendMessage(hwnd, 0x400 + 103, 1, szPath); // BFFM_SETSELECTION
  52.                     }
  53.                 }
  54.                 return 0;
  55.             }
  56.             // hwndOwner:父窗体句柄
  57.             // Title:标题;可以为null,也可以为""
  58.             // lpszInitPath:初始目录;可以为null,也可以为"";为null或""时指向“我的电脑”
  59.             // return:如果按下了“确定”按钮则为用户选择的目录,否则返回null
  60.             public static string ShowDialog(IntPtr hwndOwner, string Title, string lpszInitPath)
  61.             {
  62.                 BROWSEINFO BrInfo;
  63.                 BrInfo.hwndOwner = hwndOwner;
  64.                 BrInfo.pidlRoot = IntPtr.Zero;
  65.                 BrInfo.pszDisplayName = null;
  66.                 BrInfo.lpszTitle = Title;
  67.                 BrInfo.ulFlags = 0x0001; // BIF_RETURNONLYFSDIRS
  68.                 BrInfo.lpfn = new BrowseCallBackProc(BrowseCtrlCallback);
  69.                 BrInfo.lParam = lpszInitPath;
  70.                 BrInfo.iImage = 0;
  71.                 IntPtr pidlDestination = SHBrowseForFolder(ref BrInfo);
  72.                 string folderName = null;
  73.                 if (pidlDestination != IntPtr.Zero)
  74.                 {
  75.                     StringBuilder tmp = new StringBuilder(260); // MAX_PATH
  76.                     SHGetPathFromIDList(pidlDestination, tmp);
  77.                     folderName = tmp.ToString();
  78.                 }
  79.                 return folderName;
  80.             }
  81.         }
  82.     
  83. ///调用方法
  84. this.strItemFolder = OpenFolderDialog.ShowDialog(this.Handle, "选择目录", @"C:/");
  85.             if (strItemFolder != null)
  86.             {
  87.                 ///set select save path.
  88.                 textBox_Path.Text = this.strItemFolder;
  89.                 ///获得目录 AND 创建目录
  90.             }
  91.             else
  92.             {
  93.                 MessageBox.Show("靠,你按了“取消”按钮,啥也没选");
  94.             }
<think> 嗯,用户问的是C#中是否存在包装。这个问题其实挺有意思的,因为C#和Java的处理方式很不一样。用户可能之前接触过Java的包装(比如Integer、Double这些),所以想看看C#里有没有似的概念。 从用户提供的引用材料来看,第一个引用提到了Unity里的C#包装,主要是用来封装C++底层功能的。第三个引用更具体,展示了如何用C#包装原生C++的代码示例。这说明在C#里确实存在“包装”这个概念,但和Java的包装完全不是一回事。 用户可能混淆了两种不同的“包装”:一种是Java里对基本型的对象化包装(比如int变成Integer),另一种是C#里对非托管资源的托管封装。需要帮ta区分清楚。 先看Java式的包装:在C#里确实不需要,因为C#有更优雅的装箱拆箱机制,值型和引用型可以自由转换。比如int可以直接赋值给object,运行时自动装箱,不像Java必须显式new Integer()。这点在第二个引用里也提到了装箱拆箱的原理。 再看C#特有的包装:主要用于平台调用(P/Invoke)或封装非托管代码,就像第三个引用里的例子。这种场景下,C#包装就像个翻译官,把托管代码的调用转给非托管的C++。Unity里大量使用这种方式封装引擎功能。 用户可能是Unity开发者?因为第一个引用特意提到Unity API。如果是的话,ta实际关心的可能是如何用C#调用Unity的C++底层,而不是Java那种基础包装。 需要特别提醒内存管理的差异——C#包装非托管资源时必须处理析构,示例里用了析构函数和终结器(!ManagedClass)双重保障,这点很重要。还有字符串转换的处理(pin_ptr那段),都是C#包装的关键点。 最后生成的三个问题应该能帮用户延伸理解:对比Java包装(澄清概念差异)、Unity应用案例(贴近实际开发)、内存管理要点(避免资源泄漏)。特别是第三个问题,非托管资源处理不当会导致严重问题。 </think> 在C#中**存在包装**,但其概念和实现方式与Java中的包装(如`Integer`、`Double`等)有本质区别。以下是具体分析: --- ### 1. **与Java包装的区别** - **Java包装**:针对基本型(如`int`、`double`)提供对象化的封装(如`Integer`、`Double`),用于支持泛型、集合等场景。 - **C#包装**:主要用于**封装非托管资源(如C++库)**,为托管代码(C#)提供访问接口,而非用于封装基本型。 --- ### 2. **C#包装的核心用途** - **封装非托管代码**:通过C#包装C/C++等原生代码的功能(如Unity引擎中的底层C++接口)[^1][^3]。 - **实现跨语言互操作**:例如在Unity中,C#包装调用C++实现的物理引擎、图形渲染等底层功能。 - **简化资源管理**:通过`IDisposable`接口和析构函数确保非托管资源(如内存、句柄)的正确释放。 --- ### 3. **技术实现示例** 以下代码展示了如何用C#包装一个C++: ```csharp public ref class ManagedWrapper { private: NativeClass* _nativeInstance; // 指向C++原生对象的指针 public: ManagedWrapper() { _nativeInstance = new NativeClass(); } // 构造时创建原生对象 ~ManagedWrapper() { delete _nativeInstance; } // 析构时释放资源 // 包装方法:将C#字符串转换为C++可处理的格式 void ManagedMethod(String^ input) { pin_ptr<const wchar_t> pinnedStr = PtrToStringChars(input); _nativeInstance->NativeMethod(pinnedStr); } }; ``` > 关键点: > - `pin_ptr`:固定托管字符串内存,防止GC移动内存导致C++访问错误[^3]。 > - `ref class`:C++/CLI语法,表示托管。 > - 显式资源释放:通过析构函数确保非托管资源被回收。 --- ### 4. **关于基本型的“包装”** - C#通过**装箱(Boxing)** 将值型(如`int`)转换为引用型(`object`): ```csharp int num = 42; object boxedNum = num; // 装箱 int unboxedNum = (int)boxedNum; // 拆箱 ``` - 不需要似Java的显式包装,因为**所有型均继承自`System.Object`**。 --- ### 总结 | **特性** | Java包装 | C#包装 | |------------------|---------------------|------------------------| | **目的** | 基本型对象化 | 封装非托管资源 | | **典型场景** | 泛型集合 | 跨语言互操作(如P/Invoke)| | **内存管理** | JVM自动GC | 需显式释放非托管资源 | | **示例** | `Integer.valueOf(5)`| 封装C++的托管包装器 | 因此,C#中存在包装,但其设计目标和技术实现与Java截然不同,主要用于**桥接托管与非托管代码**而非处理基本型[^1][^3]。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值