【问题标题】:List of pointers (pointer type)?指针列表(指针类型)?
【发布时间】:2016-05-28 23:40:07
【问题描述】:

我刚开始学习 C#,我真的很喜欢那里的列表概念。我只是想知道为什么我不能列出指针。我正在尝试创建指向我的类对象的指针列表,但是当我写的时候:

List <MyClass*> mylist;

甚至:

List <int*> mylist;

VS 显示错误信息:

The type 'MyClass*" may not be used as a type argument

我不知道为什么。有什么解决办法还是完全禁止制作指针类型的列表?

(对不起,我只是在学习一些东西)

【问题讨论】:

  • c#,不是 c++/c,它掩盖了指针......所以你不能使用指针,你可以通过 val 或 ref 操作变量(它是一种指针)
  • @Proxytype 好吧,你可以,你只是不应该。通过引用传递值与 C++ 中的指针不同,它与 C++ 中的引用传递参数完全一样。两种语言具有完全相同的功能,具有相同的语义(但语法略有不同)。
  • 我只是想知道我是否可以做这样的事情,为什么不可以(出于好奇和了解更多信息)。谢谢两位的解释。

标签: c# list pointers types


【解决方案1】:

int* 甚至MyStruct* 这样的指针类型(其中MyStruct 必须是具有通常布局的值类型,其实例字段(递归地)再次是值类型)在C# 中确实存在,但在C# 中不经常使用大多数应用程序。

但是,指针类型不能用作泛型类型参数,因此List&lt;T&gt; 中的“T”不允许为int*。可以有指针数组,例如 int*[]MyStruct*[]

回答您的问题:不,没有办法将指针类型用于泛型类型参数。请注意,这不仅仅是 C# 的限制,CLR 类型系统会拒绝它(例如,typeof(List&lt;&gt;).MakeGenericType(typeof(int*)) 会抛出异常)。

与此相关的是,指针类型不像 C#/.NET 类型系统中的“普通”具体类型那样继承自 object

在 C# 中,指针仅指向值类型。对于引用类型(如使用class 声明的用户定义类型),该类型的变量或表达式的“值”是一个引用(实现-定义的内存位置)到实际实例,或 null 引用(指无实例)。这些引用有点像“指针”,但它们不允许像 int*MyStruct* 这样的真正指针那样进行算术运算(比如添加或减去内存位置,或将“地址”转换为整数)。

【讨论】:

    【解决方案2】:

    在 C# 中创建类实例列表要简单得多。您使用要存储的类或值初始化列表,然后添加实例或值。

    例如,MyClass 实例的列表将是这样的:

    List<MyClass> myList = new List<MyClass>();
    
    MyClass myClass1 = new MyClass;
    myList.Add(myClass1);
    

    或者对于一个整数:

    List<int> myList = new List<int>();
    myList.Add(123);    
    

    就是这样。不需要指针来存储类的实例。

    编辑

    在 C# 中不可能有指向引用类型或包含引用的结构类型的指针。这是因为垃圾收集器可以收集一个引用类型,即使指针指向它。这个主题在MSDN Pointer types 文章中有更详细的描述。所以 C# 不允许像 MyClass* 这样的东西。

    另外,在同一篇文章中,您可以发现唯一允许的指针类型是:sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool。

    关于int* 作为List&lt;int*&gt; 中的类型参数的问题the documentation 表示指针类型不能用作类型参数。有关详细信息,请参阅第 18.4.1 章。

    【讨论】:

    • 是的,我知道该怎么做。我只是想知道是否有这种可能性,为什么不(出于好奇和了解更多)。谢谢你。 :)
    【解决方案3】:

    正如其他答案中提到的,您不能将指针类型用作通用参数。通常,C# 中的指针只允许在“不安全”部分中使用,并且指针是非托管的——您必须自己处理它们的创建和销毁。我的猜测是,泛型不支持指针的原因是(a)它会与垃圾收集混淆,并且很容易让自己在脚上开枪,和/或(b)它只是不值得头疼语言设计者,因为指针在托管代码中应该非常少见。

    但是,在某些情况下确实会出现很多情况,例如在与旧版 C++ 代码交互时。一种有用的解决方法是“IntPtr”类。正如您所注意到的,这不会编译:

       MyClass* foo = ...;
       List <MyClass*> mylist = new List<MyClass*>();
       mylist.Add(foo);
       MyClass* bar = mylist[0];
    

    但是您应该能够通过将指针转换为 IntPtr 类型来做一个(丑陋的)解决方法:

       MyClass* foo = ...;
       List <IntPtr> mylist = new List<IntPtr>();
       mylist.Add((IntPtr)foo);
       MyClass* bar = (MyClass*)mylist[0];
    

    但在纯托管代码中,这通常不是明智之举。通常我只会在我必须与 C++ 代码互操作并且有一堆非托管结构来跟踪时才会这样做。

    【讨论】:

      【解决方案4】:

      当我搜索“C# 指针列表”时,这个问题出现了。就我而言,我想要一个List&lt;ulong*&gt;。这样的事情对我有用:

      readonly unsafe struct ULongPointer
      {
        public readonly ulong* Value;
      
        public ULongPointer(ulong* value)
        {
          Value = value;
        }
      }
      
      ulong value = 0x123UL;
      
      var listOfULongPointers = new List<ULongPointer>();
      unsafe
      {
        listOfULongPointers.Add(new ULongPointer(&value));
        *listOfULongPointers[0].Value = 0x321UL;
      }
      
      Assert.Equal(0x321UL, value);
      

      请记住,当您拥有诸如 OP 的 MyClass 之类的引用类型时,您已经在处理引用了。所以在这种情况下,你只需要一个List&lt;MyClass&gt;

      【讨论】:

        猜你喜欢
        • 2011-09-14
        • 2023-04-07
        • 2020-06-15
        • 1970-01-01
        • 2021-09-20
        • 1970-01-01
        • 2011-12-29
        • 2015-04-06
        相关资源
        最近更新 更多