Может приводить к интерфейсу, но не к типу generi c - PullRequest
0 голосов
/ 08 июля 2020

TL; DR: 1) Версия моего кода, отличная от c, позволяет мне преобразовать объект в интерфейс, который, как я знаю, он реализует; версия generi c, в которой я привожу к типу generi c, не компилируется. Мне не хватает ограничения и / или обходного пути? 2) Если C# не поддерживает то, что я делаю, есть ли другой способ достичь sh моей более широкой цели?

Самое близкое, что я подошел к поиску проблемы, похожей на мою, - это , где единственным ответом было «Это не имеет смысла, поскольку не приводит [sic] к каким-либо ограничениям». Итак, позвольте мне указать точное ограничение, с которым я сталкиваюсь ...

Вот не-общая c версия моего кода; Надеюсь, встроенные комментарии объяснят, что я пытаюсь сделать и почему:

public interface ISomeInterface
{
    string SomeFxn();
}

[Serializable]
public class SerializableInterfaceReferenceForUnity
{
    // Unity has long been able to serialize references to its own objects, but using this 
    // attribute on a "raw C#" object (i.e., anything other than Object) would try to
    // serialize the **value**.
    [SerializeField] private UnityEngine.Object unityObj;

    // This new(-ish) attribute actually allows us to serialize references ... but ONLY to
    // "raw C#" objects!  (If rawObj is a UnityEngine.Object that implements 
    // ISomeInterface, I get error messages in the console.)
    [SerializeReference] private ISomeInterface rawObj;

    // So, a kludge: branching my logic based on the type that implements ISomeInterface.
    [SerializeField] private bool objIsUnityType;

    // In my defense, I *think* the kludge will be entirely hidden on the back-end;
    // the API will "just work":
    public ISomeInterface obj
    {
        get
        {
            // FLAG: this next line works here, but breaks in generic version
            if (objIsUnityType) { return (ISomeInterface) unityObj; }
            else { return rawObj; }
        }
        set
        {
            switch (value)
            {
                case UnityEngine.Object uo:
                {
                    objIsUnityType = true;
                    unityObj = uo;
                    rawObj = null;
                    return;
                }
                default:
                {
                    objIsUnityType = false;
                    rawObj = value;
                    unityObj = null;
                    return;
                }
            }
        }
    }
}

Все вышеизложенное хорошо, но настоящая цель - позволить мне сериализовать ЛЮБОЙ интерфейс в Unity. Итак, вот общая версия c ... которая является той же строкой, за исключением того, что ISomeInterface становится TSomeInterface:

[Serializable]
public class SerializableInterfaceReferenceForUnity<TSomeInterface> 
// where TSomeInterface : { what goes here?! }
{
    [SerializeField] private UnityEngine.Object unityObj;
    [SerializeReference] private TSomeInterface rawObj;
    [SerializeField] private bool objIsUnityType;
    public TSomeInterface obj
    {
        get
        {
            //"CS0030 Cannot covert type 'UnityEngine.Object'
            // to 'TSomeInterface'" on the below:
            if (objIsUnityType) { return (TSomeInterface) unityObj; } 
            else { return rawObj; }
        }
        set
        {
            switch (value)
            {
                case UnityEngine.Object uo:
                {
                    objIsUnityType = true;
                    unityObj = uo;
                    rawObj = default;
                    return;
                }
                default:
                {
                    objIsUnityType = false;
                    rawObj = value;
                    unityObj = null;
                    return;
                }
            }
        }
    }
}

Я скрещиваю пальцы, все, что мне нужно, это ограничение на тип generi c.

За исключением этого, есть ли какое-либо обходное решение (скажем, какое-то отражение c) для изменения произвольного объекта на тип интерфейса (generi c) ?

За исключением ЭТОГО, есть ли способ достичь sh той же цели (а именно, сериализации Unity ссылок на объекты, реализующие данный интерфейс, независимо от того, являются ли эти объекты встроенными в Unity или сырые C#) чистым способом?

Также приветствуются отзывы / тухлые помидоры относительно моего кладжа.

1 Ответ

4 голосов
/ 08 июля 2020

Я ничего не знаю о Unity, но если предположить, что UnityEngine.Object является ссылочным типом, тогда вы сможете сделать что-то вроде этого:

public class SerializableInterfaceReferenceForUnity<TSomeInterface> 
       where TSomeInterface : class
{
    public TSomeInterface obj
    {
        get
        {
            if (objIsUnityType) { return unityObj as TSomeInterface; } 
            else { return rawObj; }
        }
}

Единственное, что нужно иметь в виду заключается в том, что вы не сможете использовать какой-либо тип значения (struct) в качестве общего типа c для вашего класса SerializableInterfaceReferenceForUnity.

...