简体   繁体   English

C#:通过引用传递对象的结构还是正常传递整个对象?

[英]C#: Pass a struct of an object in by reference or the entire object normally?

If I had an object of which I only needed access to a particular part of, should I pass in just that particular part or should I pass the entire object in? 如果我有一个只需要访问其特定部分的对象,我应该只传递该特定部分还是应该传递整个对象?

In my case, I'm building a game with C# using XNA and I need access to the "bounds" of the Camera class in "DrawLayer.cs", a class that draws a single layer (assuming there's multiple layers due to parallax) of the game onto the screen. 就我而言,我正在使用XNA用C#构建游戏,我需要访问“ DrawLayer.cs”中Camera类的“边界”,该类绘制一个图层(假定由于视差而存在多个图层)游戏的画面上。 The "bounds" of the camera exist as a property below: 相机的“边界”作为以下属性存在:

    public Rectangle Bounds { get { return onScreenCamera.Bounds; } }

The game is a multiplayer game that has a camera that jumps between players depending on their actions, so "onScreenCamera" references the camera that currently needs to be used. 该游戏是一款多人游戏,其摄像机会根据玩家的动作在玩家之间跳转,因此“ onScreenCamera”引用了当前需要使用的摄像机。 Also, the camera functions differently depending which player type you are, so I made an interface ICameraSetup.cs that the camera I'm discussing implements. 而且,相机的功能因您所使用的播放器类型而异,所以我创建了一个接口ICameraSetup.cs,该摄像头是我正在讨论的相机所实现的。 Here's the ICameraSetup interface: 这是ICameraSetup接口:

interface ICameraSetup
{
    Vector2 Position { get; }
    Rectangle Bounds { get; }

    void Update(GameTime pGameTime);
}

With DrawLayer.cs, I wanted to write the constructor header like this (note that Rectangle is a struct, which should mean it's a value-type): 使用DrawLayer.cs,我想像这样编写构造函数标头(请注意,Rectangle是一个结构,这应该意味着它是一个值类型):

    public DrawLayer(ref Rectangle pBounds)

and then with the constructor call, it was like this: 然后通过构造函数调用,就像这样:

    new DrawLayer(ref levelState.Camera.Bounds)

This would be passing only the bounds of the camera into DrawLayer.cs, but I seem to be getting this error: "The Property Game.Camera.ICameraSetup.Bounds has no setter." 这将仅将摄影机的边界传递到DrawLayer.cs中,但我似乎收到此错误:“ The Property Game.Camera.ICameraSetup.Bounds没有设置器。” The issue is, I don't want the interface to declare a setter for Bounds because the only class that should be able to set bounds is the Camera class and the way Bounds is set is through the private variable in the camera class, mentioned above, called "onScreenCamera". 问题是,我不希望接口为Bounds声明一个setter,因为唯一应该设置边界的类是Camera类,而设置Bounds的方法是通过camera类中的私有变量,如上所述,称为“ onScreenCamera”。

But, even if I add Set to the Bounds property, I still get this error at the DrawLayer.cs constructor call: "'ref' argument is not classified as a variable." 但是,即使我将Set添加到Bounds属性,在DrawLayer.cs构造函数调用中仍然会出现此错误:“'ref'参数未归类为变量。”

Now, one solution that I know works is to pass the entire camera into DrawLayer.cs and use bounds from there, like this: 现在,我知道可行的解决方案是将整个摄像机传递到DrawLayer.cs并从那里使用边界,如下所示:

    public DrawLayer(ICameraSetup pCamera)

then 然后

    new DrawLayer(levelState.Camera)

then use Camera.Bounds, but this seems unnecessary as all I need are the bounds in that class. 然后使用Camera.Bounds,但这似乎不必要,因为我需要的只是该类中的边界。

Another issue I might be having is with my understanding of pass-by-reference. 我可能遇到的另一个问题是我对传递引用的理解。 I understood it to be useful when you need a value-type reference to stay updated with the whatever changes are made to the value outside of the class you passed it into, but I've also read that it was the other way around: use it to change a value-type outside of where it's initially declared and have it stay the same. 我理解,当您需要一个值类型引用来保持对传入的类外部值的任何更改进行更新时,它很有用,但是我也读到它是另一回事:使用它可以在初始声明的位置之外更改值类型,并使它保持不变。

So am I making a mistake with my passing-by-reference of the Bounds of the Camera into DrawLayer? 因此,我将摄影机的边界传递给DrawLayer时是否犯了错误?

You're ignoring the first error: 您忽略了第一个错误:

A property, indexer or dynamic member access may not be passed as an out or ref parameter. 属性,索引器或动态成员访问可能不会作为out或ref参数传递。

Additionally, passing an argument by reference in this way means that it can be set, which it cannot because you define no public setter for the Bounds property. 另外,以这种方式通过引用传递参数意味着可以对其进行设置,因为您没有为Bounds属性定义公共设置器,所以不能进行设置。 So, we have two problems. 因此,我们有两个问题。

I'm confused; 我糊涂了; why are you attempting to pass it by reference to begin with? 您为什么尝试通过引用将其开头? You wish to store a reference to this object so that it can be changed later (FYI: you can't)? 您希望存储对该对象的引用,以便以后可以更改它(仅供参考:您不能)? Sounds like a poor design to me to be honest. 老实说,这听起来对我来说是一个糟糕的设计。 This doesn't seem like a performance concern, so I would suggest tweaking your design. 这似乎与性能无关,所以我建议调整您的设计。

When you run into things like this which are weird and become clunky/don't work well, it usually means you have a design problem on your hands. 当您遇到诸如此类的怪异且笨拙/无法正常工作的事情时,通常意味着您手上存在设计问题。 Don't attempt to fix that by introducing more design problems. 不要尝试通过引入更多设计问题来解决此问题。

You cannot pass a property by reference. 您不能通过引用传递属性。 This makes sense since properties are not variables - they are implemented as getter/setter methods by the compiler. 这是有道理的,因为属性不是变量-编译器将它们作为getter / setter方法实现。

You could, however, change your Bounds property into a field, or create a local variable to hold the value of Bounds, and then it would be possible to pass it with the 'ref' keyword. 但是,您可以将Bounds属性更改为字段,或者创建一个本地变量来保存Bounds的值,然后可以使用'ref'关键字将其传递。

The main reason to pass something by 'ref' is if you need to be able to alter any part of the variable, including replacing the variable with a new instance, and you expect that to be reflected in the calling code. 通过“ ref”传递内容的主要原因是,如果您需要能够更改变量的任何部分,包括用新实例替换变量,并且您希望将其反映在调用代码中。

If you just want to access Bounds, don't use 'ref'. 如果您只想访问Bounds,请不要使用“ ref”。 If Bounds is a struct, and you don't want it copied for performance reasons, consider making Bounds a class. 如果Bounds是一个结构,并且出于性能原因不希望将其复制,请考虑将Bounds设置为类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM