我们可以在C#中使用Struct作为引用类型吗?

时间:2017-12-17 12:50:26

标签: c# unity3d struct

这是Unity3D的一个例子:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParticleLauncher : MonoBehaviour {

    public ParticleSystem particleLauncher;
    public ParticleSystem splatterParticles;
    public Gradient particleColorGradient;
    public ParticleDecalPool splatDecalPool;

    List<ParticleCollisionEvent> collisionEvents;

    void Start () 
    {
        collisionEvents = new List<ParticleCollisionEvent> ();
    }

    void OnParticleCollision(GameObject other)
    {
        ParticlePhysicsExtensions.GetCollisionEvents (particleLauncher, other, collisionEvents);

        for (int i = 0; i < collisionEvents.Count; i++) 
        {
            splatDecalPool.ParticleHit (collisionEvents [i], particleColorGradient);
            EmitAtLocation (collisionEvents[i]);
        }

    }

    void EmitAtLocation(ParticleCollisionEvent particleCollisionEvent)
    {
        splatterParticles.transform.position = particleCollisionEvent.intersection;
        splatterParticles.transform.rotation = Quaternion.LookRotation (particleCollisionEvent.normal);
        ParticleSystem.MainModule psMain = splatterParticles.main;
        psMain.startColor = particleColorGradient.Evaluate (Random.Range (0f, 1f));

        splatterParticles.Emit (1);
    }

    void Update () 
    {
        if (Input.GetButton ("Fire1")) 
        {
            ParticleSystem.MainModule psMain = particleLauncher.main;
            psMain.startColor = particleColorGradient.Evaluate (Random.Range (0f, 1f));
            particleLauncher.Emit (1);
        }

    }
}

您可以在此处找到其余代码:

enter link description here

我的问题是关于EmitAtLocation()函数,在这个函数里面我们有

ParticleSystem.MainModule psMain = splatterParticles.main; 

MainModule是一个结构,我知道C#中的结构通过值而不是通过引用传递,但是这里我们有psMain变量,如果我们对该变量进行任何更改,splatterParticles.main将受到影响,它看起来像结构已经通过引用传递,是可能在C#中还是我错过了什么?

2 个答案:

答案 0 :(得分:4)

幕后有一个技巧。

首先,让我们看一下ParticleSystem.main属性:

public ParticleSystem.MainModule main
{
  get
  {
    return new ParticleSystem.MainModule(this);
  }
}

我们看到它返回一个新的MainModule结构,它以this为参数。 然后让我们看一下MainModule构造函数:

  private ParticleSystem m_ParticleSystem;

  internal MainModule(ParticleSystem particleSystem)
  {
    this.m_ParticleSystem = particleSystem;
  }

所以我们保持对ParticleSystem的引用(注意ParticleSystem是一个类)。 最后,startColor属性:

  public ParticleSystem.MinMaxGradient startColor
  {
    set
    {
      ParticleSystem.MainModule.SetStartColor(this.m_ParticleSystem, ref value);
    }
    get
    {
      ParticleSystem.MinMaxGradient gradient = new ParticleSystem.MinMaxGradient();
      ParticleSystem.MainModule.GetStartColor(this.m_ParticleSystem, ref gradient);
      return gradient;
    }
  }

简而言之,您的ParticleSystem.MainModule对象实际上并不存储任何内容。它只是全局共享ParticleSystem对象的包装器。每当您访问ParticleSystem.MainModule上的媒体资源时,它都会直接修改共享的ParticleSystem。因此,你看到的混乱行为。

答案 1 :(得分:3)

考虑使用ref关键字。有了它,您可以通过引用传递任何值类型参数(而不是通过复制)。

https://www.dotnetperls.com/ref

  

参考。 ref参数作为引用传递,而不是值。这意味着您可以在被调用的方法中分配参数,并在调用站点分配该参数。

还要考虑阅读out keyword

  

出。此C#关键字表示引用参数。有时候方法必须返回多个值,而不是存储类状态。

不要在他们之间感到困惑:

When to use ref vs out