存储对象的引用

16

这可能是一个有点奇怪的问题,但我想知道是否有人可以帮忙...

在 C++ 中,我可以像这样做:

class MyOtherClass
{
     private:
         MyLogger* logger;
     public:
         MyOtherClass (MyLogger* logger)
              : logger (logger)
         {}
};

class MyClass
{
     private:
         MyLogger* logger;
     public:
         MyClass (MyLogger* logger)
              : logger (logger)
         {}
};

int main (int c, char** args)
{
    MyLogger* logger = new MyLogger ();
    /* Code to set up logger */
    MyOtherClass* myOtherClass = new MyOtherClass (logger);
    MyClass* myClass = new MyClass (logger);
}

为了使得其他对象(myOtherClass和myClass)都包含指向logger的指针,这样它们就会调用相同的logger类。然而,在C#中我该如何做到同样的事情?是否有一种方式可以存储对全局对象的引用或指针?我猜在C#中,如果我做了什么像

public class MyClass
{
     private MyLogger logger = null;

     public MyClass (MyLogger _logger)
     {
         logger = _logger;
     }
};

那么它实际上是将类变量logger分配给_logger的一个副本吗?还是我把事情搞混了:S

非常感谢任何帮助,提前致谢!


你应该了解一下单例模式:http://en.wikipedia.org/wiki/Singleton_pattern - RvdK
2
我不知道为什么单例与此有关。据我所知,你可以拥有多个记录器,没有任何理由不能这样做。 - R. Martinho Fernandes
单例模式通常是一种反模式。请参见 https://dev59.com/OWcs5IYBdhLWcg3wjUuR。 - Rob K
4个回答

22

C# 中实际上要简单得多。

基本上,你可以这样做:

MyLogger logger = new MyLogger();
MyOtherClass myOtherClass = new MyOtherClass(logger);
MyClass myClass = new MyClass(logger);

在C#中,类基本上是作为引用(实际上是指针)保存的。在这个代码片段中,您将引用传递给logger的两个对象的构造函数。该引用相同,因此每个实例都有相同的MyLogger实例。

在这种情况下,您几乎只需要删除指针语法 =D


是的,我也认为是这样,但后来我想这不可能这么简单!这大概是在你更习惯 C++ 而非 C# 的时候会发生的事情 :P - KingTravisG
1
是的。与C++相比,其中一个基本的陷阱是对象变量在底层实际上是指针...大多数情况下是这样。当然总有例外 =D - Tejs
1
啊,对了,所以基本上在C#中,MyLogger logger = new MyLogger()相当于C++中的MyLogger* logger = new MyLogger()? - KingTravisG
1
你不需要任何特殊的修饰符。从技术上讲,所有引用都是按值传递的,这意味着指针值被复制并传递,但仍然是对实际实例的引用。只有当您想要通过引用传递对象指针时,才需要使用“ref”,将实例的实际引用传递给方法。通常在您希望在方法内更改对实例的引用时使用它。当按值传递时,您的方法可以在内部分配新引用,但在该方法的范围之外,实际引用没有改变。 - Tejs
1
@SCassidy1986 使用ref关键字相当于在C++中传递一个指向对象的指针。如果这确实是你所需要的(即你需要能够在函数中更改指针所指向的内容,而不是修改底层对象),那就这样吧。不过这种情况很少见。 - Servy
显示剩余4条评论

4
你把事情搞混了。在C#中,赋值语句如下:
    logger = _logger;

复制引用,而不是对象。执行此语句后,仍然(最多)只有一个MyLogger - 现在由两个对象变量引用


啊,我现在明白了。我有点新手C#,之前一直在用C++,好像忘记了C# :( - KingTravisG

2
如果类型是引用类型(也就是类),那么你复制的是引用,而不是对象本身。
相对于引用类型,你还有值类型。值类型基本上就是基本类型:int,double等等。
在你的情况下,这意味着当你从类或外部调用方法访问它时,你将使用相同的对象,因为你的目标是引用对象。

string 是一个引用类型。 - R. Martinho Fernandes
它实际上表现为值类型。如果您将字符串传递给方法,并在此方法中更新字符串,则调用方法的值不会更改。在这里,Eric Lippert解释了这个决定 - Steve B
我不知道你在说什么:你根本无法改变字符串。 - R. Martinho Fernandes
这是一件好事。我的意思是,如果你调用 string s = "hello";SomeMethod(s);,无论某个方法对参数做了什么,s 总是会是 "Hello"。 - Steve B
是的,这意味着“如果您在此方法中更新字符串”毫无意义。 - R. Martinho Fernandes
显示剩余4条评论

0

添加注释以备将来我也会忘记,同时为了那些想要可视化“C++指针”与“C#对象引用”以及“通过引用传递的C#对象引用”的新手提供帮助。 请注意,通过引用传递(最后一种方法调用)和分配新对象会更改原始对象。

using System;

public class Emp
{
    public int TimeSpentInCompany {get; set;}
}

public class Program
{
    public static void Main()
    {
        
        Emp t1 = new Emp{TimeSpentInCompany = 5};
        Console.WriteLine("original obj before method call-->" + t1.TimeSpentInCompany);
        
        // Test is one by one
        
        // var res = PassObject_SimpleUpdateMemberAndPrint(t1);
        // var res = PassObject_SimpleUpdateObjectAndPrint(t1);
        // var res = PassObjectByRef_SimpleUpdateMemberAndPrint(ref t1);
        var res = PassObjectByRef_SimpleUpdateObjectAndPrint(ref t1);
        
        Console.WriteLine("original obj after method call-->" + t1.TimeSpentInCompany);
        Console.WriteLine("obj from method response-->" + res.TimeSpentInCompany);
    }
    
    static Emp PassObject_SimpleUpdateMemberAndPrint(Emp data)
    {
        /*
            original obj before method call-->5
            in method before modification obj member--> 5
            in method AFTER modification obj member--> 9
            original obj after method call-->9
            obj from method response-->9
        */      
        Console.WriteLine("in method before modification obj member--> "+ data.TimeSpentInCompany);
        data.TimeSpentInCompany += 4;
        Console.WriteLine("in method AFTER modification obj member--> "+ data.TimeSpentInCompany);
        return data;
    }   
    
    static Emp PassObject_SimpleUpdateObjectAndPrint(Emp data)
    {
        /*
            original obj before method call-->5
            in method before assigning new obj --> 5
            in method AFTER assigning new obj --> 9
            original obj after method call-->5
            obj from method response-->9
        */
        Console.WriteLine("in method before assigning new obj --> "+ data.TimeSpentInCompany);
        data = new Emp{TimeSpentInCompany = 9};
        Console.WriteLine("in method AFTER assigning new obj --> "+ data.TimeSpentInCompany);
        return data;
    }
    
    static Emp PassObjectByRef_SimpleUpdateMemberAndPrint(ref Emp data)
    {
        /*
            original obj before method call-->5
            in method before modification obj member--> 5
            in method AFTER modification obj member--> 9
            original obj after method call-->9
            obj from method response-->9
        */      
        Console.WriteLine("in method before modification obj member--> "+ data.TimeSpentInCompany);
        data.TimeSpentInCompany += 4;
        Console.WriteLine("in method AFTER modification obj member--> "+ data.TimeSpentInCompany);
        return data;
    }   
    
    static Emp PassObjectByRef_SimpleUpdateObjectAndPrint(ref Emp data)
    {
        /*
            original obj before method call-->5
            in method before assigning new obj --> 5
            in method AFTER assigning new obj --> 9
            original obj after method call-->9
            obj from method response-->9
        */
        Console.WriteLine("in method before assigning new obj --> "+ data.TimeSpentInCompany);
        data = new Emp{TimeSpentInCompany = 9};
        Console.WriteLine("in method AFTER assigning new obj --> "+ data.TimeSpentInCompany);
        return data;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接