让.Net 值类型具有引用传递的行为

[说明:这里讲的并不是作为函数参数的情形,那样只要用C#的 ref  或者 out 关键字。]

1. C#unsafe 指针既不优雅,更有不少限制。所以不用他了,那么只能用interface 间接实现了。

using System;

using System.Collections.Generic;

 

public interface IByRefStruct

{

    int Data {

        get;

        set;

    }

}

 

public struct ByRefStruct : IByRefStruct

{

    private int data;

 

    public ByRefStruct(int data) {

        this.data = data;

    }

 

    public int Data {

        get {

            return this.data;

        }

        set {

            this.data = value;

        }

    }

 

    public override string ToString() {

        return this.data.ToString();

    }

}

 

internal static class Program

{

    private static readonly int N = 3;

 

    private static void Main() {

        IList<ByRefStruct> listStruct = new List<ByRefStruct>();

        for (int i = 0; i < N; i++) {

            listStruct.Add(new ByRefStruct(i + 1));

        }

 

        Console.WriteLine("Test struct in List:");

 

        Console.WriteLine("Initial data:", Environment.NewLine);

        Print(listStruct);

 

        for (int i = 0; i < listStruct.Count; i++) {

            ByRefStruct tmp = listStruct[i];

            tmp.Data = listStruct.Count - i;

 

            // This statement is neccesary

            listStruct[i] = tmp;

        }

 

        Console.WriteLine("{0}Modified data:", Environment.NewLine);

        Print(listStruct);

 

 

        IList<IByRefStruct> listInterface = new List<IByRefStruct>();

        for (int i = 0; i < N; i++) {

            listInterface.Add(new ByRefStruct(i + 1));

        }

 

        Console.WriteLine("{0}{0}Test interface in List:", Environment.NewLine);

 

        Console.WriteLine("Initial data:", Environment.NewLine);

        Print(listInterface);

 

        for (int i = 0; i < listStruct.Count; i++) {

            IByRefStruct tmp = listInterface[i];

            tmp.Data = listInterface.Count - i;

 

            // Now we do not need this statement

            // listInterface[i] = tmp;

        }

 

        Console.WriteLine("{0}Modified data:", Environment.NewLine);

        Print(listInterface);

    }

 

    private static void Print(IList<ByRefStruct> list) {

        foreach (ByRefStruct byRefStruct in list) {

            Console.Write("{0} ", byRefStruct);

        }

    }

 

    private static void Print(IList<IByRefStruct> list) {

        foreach (IByRefStruct byRefStruct in list) {

        Console.Write("{0} ", byRefStruct);

        }

    }

}

 

2. 使用C++/CLI 值类型的强类型装箱实例,示例如下:

 

 

 

using namespace System;

using namespace System::Collections::Generic;

 

public value class ByRefStruct

{

private:

    int data;

public:

    ByRefStruct(int);

    virtual String^ ToString() override;

    property int Data {

       int get();

       void set(int);

 }

};

 

ByRefStruct::ByRefStruct(int data) {

    this->data = data;

}

 

String^ ByRefStruct::ToString() {

    return this->data.ToString();

}

 

int ByRefStruct::Data::get() {

    return this->data;

}

 

void ByRefStruct::Data::set(int value) {

    this->data = value;

}

 

const int N = 3;

void Print(IList<Object^>^);

 

int main() {

     IList<Object^>^ list = gcnew List<Object^>();

     for (int i = 0; i < N; i++) {

        list->Add(gcnew ByRefStruct(i + 1));

     }

 

     Console::WriteLine("Initial data:");

     Print(list);

 

     for (int i = 0; i < list->Count; i++) {

          ByRefStruct^ byRefStruct = (ByRefStruct^)list[i];

          byRefStruct->Data = list->Count - i;

 

          // Also do not need this statement

          // list[i] = byRefStruct;

     }

 

     Console::WriteLine("{0}Modified data:", Environment::NewLine);

     Print(list);

 

     return 0;

}

 

void Print(IList<Object^>^ list) {

     for each (Object^ obj in list) {

        Console::Write("{0} ", obj);

     }

}

 

 

    C# 中,我们使用ByRefStruct tmp = listStruct[i],中间发生了一个copy 操作,数据

 

已不是原来的那个了,而使用interface 的时候,由于interface 是引用类型,所以他在托管

 

堆中分配内存,IByRefStruct tmp = listInterface[i],取到的是一个托管堆中的对象,并没

 

有发生copy 操作,所以修改起作用。

 

   而在C++/CLI 中,我们使用ByRefStruct^ temp = (ByRefStruct^)list[i]; 中间发生了

 

unbox,也没有发生copy操作,而数据还位于托管堆中,但是类型却是ByRefStruct^,这样我

 

们就可以直接获取ByRefStruct Data 成员,这就是所谓的值类型的强类型装箱实例

 

这在C#中是不能做到的。

 

posted on 2007-12-22 16:38  优哉@游哉  阅读(430)  评论(2编辑  收藏  举报

导航