C# C语言中的指针替换#

C# C语言中的指针替换#,c#,.net,pointers,C#,.net,Pointers,我需要为C#中类似C/C++的指针提供一个替代方法,以便存储在构造函数中传递的变量的引用。我希望本地指针在每次引用值更改时都更改其值。就像一个指针。但我不想在C#中使用真正的指针,因为它们不安全。有解决办法吗 class A { public Int32 X = 10; } class B { public B(Int32 x) { Y = x; }

我需要为C#中类似C/C++的指针提供一个替代方法,以便存储在构造函数中传递的变量的引用。我希望本地指针在每次引用值更改时都更改其值。就像一个指针。但我不想在C#中使用真正的指针,因为它们不安全。有解决办法吗

    class A
    {
        public Int32 X = 10;
    }

    class B
    {
        public B(Int32 x)
        {
            Y = x;
        }

        public Int32 Y { get; set; }
    }
    static void Main(string[] args)
    {
        A a = new A();
        B b = new B(a.X);

        Console.WriteLine(b.Y); // 10
        a.X = 11;
        Console.WriteLine(b.Y); // 10, but I want it to be 11
    }

我对C不太熟悉,所以我无法提供有效的答案,但C中肯定存在指针

int*ptr=&a


看看文档:

忘记指针,开始用C#思考,同时用C#:D编码

我会这样做:

public interface IXProvider
{
     int X {get;}
}

class A : IXProvider
{
    public int X {get; set;} = 10;
}

class B
{
    public B(IXProvider x)
    {
        _x = x;
    }

    private readonly IXProvider _x;
    public int Y => _x.X;
}

static void Main(string[] args)
{
    A a = new A();
    B b = new B(a);

    Console.WriteLine(b.Y); // 10
    a.X = 11;
    Console.WriteLine(b.Y); // 11
}
class Obj {
    public int Val;
}

void Main() {
    Obj o1 = new Obj();
    o1.Val = 5;
    Obj o2 = o1;
    o2.Val = 8;
//o1.Val is 8 now
}
class B
{
    private A _a;
    
    public B(A a)
    {
        _a = a;       
    }

    public A GetA() { 
        return _a; 
    }     

    public void SetA(A value) { 
        _a = value;
    }      
}
位图示例:(为简单起见,假设“SomeBitmap”和“AnotherBitmap”是实际位图)


值tpe(如
int
)与参考类型(如
MyClass
)之间存在巨大差异。由于您实际上对
位图
感兴趣,而是一种引用类型,因此不需要执行任何指针逻辑。变量已经是引用。更改其状态(例如通过修改其任何公共属性)将反映在所有其他引用中

因此,当您的类
A
具有类型为
Bitmap
的变量时,您也可以从任何其他代码中使用该变量(假设您可以访问该成员,例如,当该成员是
private
时,您肯定不能)


更好的方法是将值类型包装为引用类型。考虑这一点:

object o1 = new object();
object o2 = o1;
现在您可以这样使用它:

public interface IXProvider
{
     int X {get;}
}

class A : IXProvider
{
    public int X {get; set;} = 10;
}

class B
{
    public B(IXProvider x)
    {
        _x = x;
    }

    private readonly IXProvider _x;
    public int Y => _x.X;
}

static void Main(string[] args)
{
    A a = new A();
    B b = new B(a);

    Console.WriteLine(b.Y); // 10
    a.X = 11;
    Console.WriteLine(b.Y); // 11
}
class Obj {
    public int Val;
}

void Main() {
    Obj o1 = new Obj();
    o1.Val = 5;
    Obj o2 = o1;
    o2.Val = 8;
//o1.Val is 8 now
}
class B
{
    private A _a;
    
    public B(A a)
    {
        _a = a;       
    }

    public A GetA() { 
        return _a; 
    }     

    public void SetA(A value) { 
        _a = value;
    }      
}

NET中基本上有3种类型的引用

  • 对象引用(即
    a
    类型的本地/参数/字段,其中
    a
    是引用类型-a
    接口
    委托
    等)
  • 非托管指针(即
    Foo*
    类型的本地/参数/字段)
  • 托管指针(即
    ref Foo
    类型的本地/参数)
  • 您(非常明智地)说您不想使用“2”,而“3”只能在堆栈上使用(作为局部变量或参数),因此剩下“1”,这是可能的。例如,通过传入
    A
    对象实例而不是
    int
    。请参阅@Fildor的答案,了解这方面的演练。

    C#区分了值类型和引用类型。值类型(除了
    string
    1之外的结构和基元类型)通过值传递(复制),而引用类型(类)本质上是花哨的指针。(顺便说一句,在IDE中,如果将鼠标悬停在变量上,它将告诉您它是类还是结构)

    因此,请记住,您的代码就是这样做的:

    class A       // reference type
    {
        public Int32 X = 10;     // with a value type field
    }
    
    class B       // reference type
    {
        // The ctor takes in a value type parameter; a copy of the 
        // value is passed in (pretty much like in C++)
        public B(Int32 x)
        {
            Y = x;       // this now contains its own copy
        }
    
        // value type PROPERTY -- see below
        public Int32 Y { get; set; }
    }
    
    所以,在你的主要方法中

    A a = new A();
    B b = new B(a.X);
    
    A a = new A();
    B b = new B(a);
    
    b、 Y与a.X没有连接,因为构造函数在计算a.X后立即获得a.X的副本

    您可以做的最简单的事情是让B的构造函数接受a类型的参数,然后在内部存储对a的引用:

    class B
    {
        private A _a;
        
        public B(A a)    // a is passed in by reference
        {
            _a = a;       
        }
    
        public Int32 Y { 
            get => _a.X; 
            set => _a.X = value; 
        }     
    }
    
    现在当你这么做的时候

    A a = new A();
    B b = new B(a.X);
    
    A a = new A();
    B b = new B(a);
    
    a
    指的是
    b
    内外的同一对象。更改
    a.X
    将影响调用
    b.Y
    的结果

    您还可以直接公开
    a

    class B
    {
        public B(A a)
        {
            A = a;
        }
    
        public A A { get; set; }
    }
    
    那么主要是:

    关于属性的注记 您应该知道字段和属性之间的区别。字段是数据成员,就像C++一样。属性只是编译器在幕后生成的get/set方法对的一些语法糖。大致相当于这样的东西:

    public interface IXProvider
    {
         int X {get;}
    }
    
    class A : IXProvider
    {
        public int X {get; set;} = 10;
    }
    
    class B
    {
        public B(IXProvider x)
        {
            _x = x;
        }
    
        private readonly IXProvider _x;
        public int Y => _x.X;
    }
    
    static void Main(string[] args)
    {
        A a = new A();
        B b = new B(a);
    
        Console.WriteLine(b.Y); // 10
        a.X = 11;
        Console.WriteLine(b.Y); // 11
    }
    
    class Obj {
        public int Val;
    }
    
    void Main() {
        Obj o1 = new Obj();
        o1.Val = 5;
        Obj o2 = o1;
        o2.Val = 8;
    //o1.Val is 8 now
    }
    
    class B
    {
        private A _a;
        
        public B(A a)
        {
            _a = a;       
        }
    
        public A GetA() { 
            return _a; 
        }     
    
        public void SetA(A value) { 
            _a = value;
        }      
    }
    
    在本例中,由于A是引用类型,因此它是通过getter的引用返回的。但是现在假设A被声明为struct(值类型)。然后getter将返回一个副本。这有时会导致一个对C#初学者来说并不明显的问题

    struct A       // value type
    {
        public Int32 X;     // with a value type field
        public A(Int32 x) { X = x; }
    }
    
    如果A是一个struct,那么

    b.A.X=11

    您将得到一个编译器错误:“无法修改'b.a.X'的返回值,因为它不是变量”

    原因是
    b.A
    返回了一份副本,因此如果您在其中更改了
    X
    ,则该行之后的更改将丢失。您必须替换整个
    实例:

    A a = new A(10);   // struct
    B b = new B(a);    // class containing a struct
    
    
    Console.WriteLine(b.A.X);   // 10
    
    a.X = 11;
    Console.WriteLine(b.A.X);   // 10  - because A is a value type now
    
    b.A = new A(11);            // setting a property on B works as expected,
                                // but you can't do b.A.X = 11
    
    Console.WriteLine(b.A.X);   // 11
    
    另外,在C#中,您通常会编写
    int
    ,而不是
    Int32



    1
    string
    是引用类型,但是它是不可变的(所有“修改”字符串的操作都返回单独的
    string
    实例)。

    您可以通过将引用传递给
    a
    而不是
    int
    ,来解决此问题,然后您可以执行
    public int Y=>a.X
    X
    值按值传递到ctor。您可以在B的ctor中使用
    ref
    关键字,使ctor参数通过引用而不是通过值传递。在任何情况下,如果你要传递一个
    Bitmap
    类型的参数,我看不出让程序保持现状有什么问题,因为
    Bitmap
    是一个引用类型,所以你已经有了引用(和指针).所有不是从
    ValueType
    继承的内容都是pointer@HimBromBeere完全同意你的第一个修正-迂腐的观点,尽管:“无论如何它是通过引用传递的”-不,值是引用,通过值我需要…但我不想一旦你学会了C#basics,这些被误导的情绪和想法就会消失。你需要为此使用不安全。是的,但在C#中,你需要将其声明为“不安全”,我想绕过它是的,这是存在的,但在使用
    不安全
    代码时,你需要非常非常小心。在本例中,OP希望将其存储为字段。如果您正在谈论的是一个“内部指针”(即您需要使用
    fixed
    来获得的东西),那么这将导致灾难,因为在
    fixed
    块结束时,该值应被视为死值,因为此时GC可以移动原始对象(以及您的非托管po)