RSS 2.0 Feed
2004-12 Entries
摘要:最近灵感之源大哥常常在MSN中向我倾诉移植VB6代码的痛苦过程。我一看他的代码——好家伙,这都是原先在VB6种最高深的用法。什么不安全的指针啊,复制内存啊,一应俱全。调用平台的时候指针是少不了的,而VB.NET又不支持,所以麻烦常来,确实让人感到痛苦。我建议他用C#或者MC++,可是他愿意更纯的VB,那只好我来做了。为了能够让指针操作得以在VB中进行,必须对他们进行封装,泛型在这里是个很好的选择。而C#根本不允许对泛型的类型参数使用指针,那我们只有C++/CLI了。 C++/CLI支持两种托管的指针:内部指针和顶指针。内部指针(stdcli::language::interior_ptr)是一个指向托管堆中对象的动态指针。当托管堆中对象发生移动时,内部指针可以同步得到更新。内部指针具有很到的灵活性,他可以和C++本地指针进行类型转换,还可以进行指针运算。定指针(stdcli::language::pin_ptr)也是在一种指向托管堆对象的指针,被定指针所指的对象将被“定”在内存中,CLR不能移动它在内存中的位置,因此定指针可以用来向非托管的代码传递托管对象的指针,它能确保非托管代码操作的时候对象不会移动。最令人欣喜的就是,无论是定指针还是内部指针,他们都能对泛型的类型参数进行操作。所以我们可以封装一段代码来操作指针: ref class PointerHelper sealed{    private:    PointerHelper(void)    {    }    public:    generic<typename T> where T : System::ValueType    static T GetValue(IntPtr address)    {        return *(interior_ptr<T>)(void *)address;    }    generic<typename T> where T : System::ValueType    static void UnsafeSetValue(IntPtr address, T value)    {        interior_ptr<T> ptr = (interior_ptr<T>)(void*)address;        *ptr = value;    }    generic<typename T>where T : System::ValueType    static IntPtr UnsafeGetAddress(T %value)    {        pin_ptr<T> pp = &value;        return IntPtr((void*)pp);    }}; 我也不太确定这段代码会是什么效果,来试验一下。这是一段VB的代码: Dim x As IntegerDim p As IntPtr = PointerHelper.UnsafeGetAddress(x)PointerHelper.UnsafeSetValue(p, 123)MsgBox(x.ToString) 运行下看x的值,真的变了。相信有了这个,灵感之源所遇到的痛苦应该可以减弱一点了吧。至少从指针里获取指的操作不需要复制内存来做了。以前无法获取变量的地址现在也可以做到了。灵感之源只需要耐心等到VS2005发布,就可以轻松使用这段代码,逃离苦海了。 不过……这样使用终归是不安全的。VB对指针的类型没有任何检查和约束,我也没办法把这个东西做成强类型的。如果有人愿意,他完全可以这样写 Dim x As LongDim p As IntPtr = PointerHelper.UnsafeGetAddress(x)PointerHelper.UnsafeSetValue(p, 123.0F)MsgBox(PointerHelper.GetValue(Of Guid)(p).ToString) 这完全是可以运行的,把123.0F的浮点数塞到整型变量的地址里,然后按照Guid取出……不难想象若这种东西滥用起来,就会再次恢复到VB6那种“大师级”无法阅读、维护的代码了。...[阅读全文]

posted @ | Feedback (9) | Filed Under [ 技术随笔 灵感记录 ]

摘要:用Enum的时候,可能会有要遍历Enum中所有已定义值的功能。而当前各种.NET语言都没有提供对此需求的语法支持。我们只能用Enum.GetValues来实现这个任务。但是,Enum.GetValues一来是要用到运行时类型信息,让人不爽;二来得到的数组不直接是所需枚举类型的,需要转换。最好有一种强类型的语法可以帮助我们做这件事。所以,我就写了这个简单的小程序。其实内部还是得用Enum.GetValues,但是只在第一次使用时调用,后面就将这个取得的值集合保存起来,即使多次使用也不会担心性能受损。这个程序用C++/CLI BETA1写成,不适用于C++/CLI CTP或Tools Update。用C++的原因是,C#和VB.NET都对泛型约束语法做了过分的限制,让我写不了这个程序…… 首先是ValueCollection类: generic<typename T> where T : System::Enum[DefaultMember("Item")] //让Item属性成为默认属性(C#中的索引器)public ref class EnumValueCollection : public IEnumerable<T>{    private:    initonly array<T>^ values;    IEnumerator<T>^ enumerator;    protected:    virtual IEnumerator<T>^ GetValuesEnumerator() = IEnumerable<T>::GetEnumerator    {        if (!enumerator)        {            enumerator = ((IEnumerable<T>^)values)->GetEnumerator();        }        return enumerator;    }    private public: // internal: in future version    EnumValueCollection(void)    {        values = (array<T>^)Enum::GetValues(typeid<T>);    }    public:    property T Item[] //参数化属性    {        T get(int index)        {            try            {                return values[index];            }            catch(Exception^ e)            {                throw gcnew ArgumentOutOfRangeException("index",                     "This enum does not contain a value of this index");            }        }    }}; 接下来要有一个维护ValueCollection实例Singleton的帮助类: generic<typename T> where T : System::Enumpublic ref class EnumHelper sealed{    private:    EnumHelper()    {        //不能创建此类的实例   ......[阅读全文]

posted @ | Feedback (5) | Filed Under [ 灵感记录 ]