【问题标题】:Despite class/runtimetpye match, assignment fails尽管类/运行时类型匹配,但分配失败
【发布时间】:2019-07-03 20:09:27
【问题描述】:

EF 继承自 E
SF 继承自 S
S 具有 E 类型的属性 subE
EF 类型的运行时 obj 从其祖先类 (E) 调用 AddS(S arg) - 传递类型 (SF) 的运行时 obj
分配尝试在 AddS 中:arg.subE = this
从附加的图像中,您可以看到运行时类型匹配,但分配失败。

图像键:E - 事件; EF - EventFrameChange; S - 订户; SF - SubscriberFrameChange; AddS() - 添加订阅者; subE - 订阅事件

最小的、完整的和可验证的例子

此代码适用于 Unity。在场景中创建一个空的 GameObject 并添加一个 SpriteAnimatorScript 作为组件。

using UnityEngine;

public abstract class Event : ScriptableObject
{
    public Subscriber[] subscribers;

    public void AddSubscriber(Subscriber aSub)
    //
    {
        aSub.subscribedEvent = this;
    }
}

using UnityEngine;

public class EventFrameChange : Event
{
    private SpriteAnimatorScript animatorScript;

    public void Initialize()
    // ^ 
    {
        subscribers = new Subscriber[0];
    }

}

using UnityEngine;

public abstract class Subscriber : ScriptableObject
{
    public Event subscribedEvent;
    // ^ Event this is a subscription to.

    public virtual void SetEvent(Event aEvent)
    {
        subscribedEvent = aEvent;
    }

}

using UnityEngine;

public class SubscriberFrameChange : Subscriber
{
    public new EventFrameChange subscribedEvent;
}

using UnityEngine;

public class SpriteAnimatorScript : MonoBehaviour 
{
    public EventFrameChange eventFrameChange;

    public SubscriberFrameChange subscriberFrameChange;

    void Start () 
    {
        SetupEvents();
    }

    private void SetupEvents()
    {
        eventFrameChange = ScriptableObject.CreateInstance<EventFrameChange>();
        subscriberFrameChange = ScriptableObject.CreateInstance<SubscriberFrameChange>();
        eventFrameChange.AddSubscriber(subscriberFrameChange);
    }

}

【问题讨论】:

  • 请编辑您的问题以包含一个minimal reproducible example 来演示问题。见How to Asktour
  • 我不是 StackExchange 的常客 - 我希望我的代码交付和说明清晰、恰当。
  • 看来我基本上是在自言自语。一些添加的信息:像这样显式转换 Event.AddSubscriber:aSub.subscribedEvent = (EventFrameChange)this - 导致分配成功。虽然它也打破了继承结构。
  • 如果我将代码放入一个普通的 C# 控制台应用程序(因缺少 Unity 而进行调整),我看到 aSub 有两个名为 subscribedEvent 的属性,因为您的 new 字段只是阴影旧的(见answer)。尽管它在那个环境中呈现出一些不同,但可能是相关的。如果在该图中,您扩展了aSubbase,它会显示另一个具有非空值的字段吗?
  • @PhilM 是的!扩展基数时有一个非空版本。 Hrm - 我想我可以去掉 new 属性,然后在后代中使用该字段时进行显式转换 - 这听起来合理吗?

标签: c# inheritance


【解决方案1】:

如果我将代码放入一个普通的 C# 控制台应用程序(因缺少 Unity 而进行调整),我看到 aSub 有两个名为 subscribedEvent 的属性,因为您的 new 字段只是遮住了旧的。所以基类方法内的赋值是赋值给该字段的基类副本。

【讨论】: