Unable to Load assets using an interface type parameter, e.g. LoadAssetAsync<IMyInterface>

public interface IModelAsset<TModel>
{
    TModel Model { get; }
}

[Serializable]
public class Instruction
{
    public string[] words;
}

public class InstructionAsset : ScriptableObject, IModelAsset<Instruction>
{
    [SerializeField]
    private Instruction _model;

    public Instruction Model =>
        _model;
}

public class Main
{
    public static void LoadInstruction()
    {
        // This works
        Addressables.LoadAssetAsync<InstructionAsset>("instruction");
        // This doesn't work
        Addressables.LoadAssetAsync<IModelAsset<Instruction>>("instruction");
    }
}

Above is some sample code illustrating the issue. The error I receive is KeyNotFound. My usecase is writing a helper method to handle the Release() call for my assets that can be converted to internal models.

Is this intended behavior or a known limitation?

It could be a limitation of underlying asset bundle LoadAssetAsync(name, type) method that don’t play well with interface.

BundledAssetProvider.cs

As well as in fast mode (AssetDatabaseProvider.cs), the highlighted line failed on interface.

2 Likes

That’s really enlightening. I assumed that inherited types would be returned, but I see that isn’t supported. The following tests succeed.

// Base.cs
using UnityEngine;

[CreateAssetMenu(menuName = "Base")]
public class Base : ScriptableObject
{ }
// Derived.cs
using UnityEngine;

[CreateAssetMenu(menuName = "Derived")]
public class Derived : ScriptableObject
{ }
// AddressableTest.cs
using System.Collections;
using System.Text.RegularExpressions;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.TestTools;

public class AddressableTest
{
    [UnityTest]
    public IEnumerator AddressablesShouldNotReturnDerivedAsBase()
    {
        LogAssert.Expect(LogType.Error, new Regex("InvalidKeyException"));
        var operation = Addressables.LoadAssetAsync<Base>("Derived");
        yield return operation;
        Assert.IsNull(operation.Result);
    }

    [UnityTest]
    public IEnumerator AddressablesShouldReturnDerivedAsDerived()
    {
        var operation = Addressables.LoadAssetAsync<Derived>("Derived");
        yield return operation;
        Assert.IsNotNull(operation.Result);
    }
}

Derived : Scriptable => Derived : Base?

It shall work after the fix.

1 Like

Woops! Thanks!

I went ahead and sent in a bug report. It makes sense to me that the intention of Addressables.LoadAssetAsync<TAsset>() is to return any addressable assets that inherit from TAsset to keep it consistent in the conditions that TAsset : UnityEngine.Object and TAsset : interface.

If the behavior is not intended to be consistent between the two cases, please let me know!

1 Like