可以转换为接口,但不能转换为泛型
Can cast to interface, but not to generic type
TL;DR: 1) 我的代码的非泛型版本允许我将对象转换为我知道它实现的接口;一个通用版本,我在其中转换为通用类型,将无法编译。我是否缺少一个约束 and/or 解决方法? 2) 如果 C# 不支持我正在做的事情,是否有其他方法可以实现我更广泛的目标?
我最接近发现与我自己的问题类似的问题是 this,其中唯一的答案是“这没有任何意义,因为它不会导致 [原文如此] 受到任何限制。”那么,让我详细说明我面临的确切限制...
这是我的代码的非通用版本;希望内联评论能解释我正在尝试做什么,以及为什么:
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 中的任何界面。所以,这是一个通用版本......它是相同的行,除了 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;
}
}
}
}
}
我祈祷我所需要的只是对泛型类型的约束。
除此之外,是否有任何变通方法(例如,一些反射魔法)将任意对象更改为(通用)接口类型?
除此之外,是否有任何方法可以实现相同的 objective(即对实现给定接口的对象的引用的 Unity 序列化,无论这些对象是否是 Unity 内置的- ins 或原始 C#) 以一种干净的方式?
也欢迎反馈/烂番茄关于我的kludge。
我对Unity一无所知,但假设UnityEngine.Object
是一个引用类型,那么你应该可以这样做:
public class SerializableInterfaceReferenceForUnity<TSomeInterface>
where TSomeInterface : class
{
public TSomeInterface obj
{
get
{
if (objIsUnityType) { return unityObj as TSomeInterface; }
else { return rawObj; }
}
}
唯一要记住的是,您将无法使用任何值类型 (struct
) 作为您的 SerializableInterfaceReferenceForUnity
class.
TL;DR: 1) 我的代码的非泛型版本允许我将对象转换为我知道它实现的接口;一个通用版本,我在其中转换为通用类型,将无法编译。我是否缺少一个约束 and/or 解决方法? 2) 如果 C# 不支持我正在做的事情,是否有其他方法可以实现我更广泛的目标?
我最接近发现与我自己的问题类似的问题是 this,其中唯一的答案是“这没有任何意义,因为它不会导致 [原文如此] 受到任何限制。”那么,让我详细说明我面临的确切限制...
这是我的代码的非通用版本;希望内联评论能解释我正在尝试做什么,以及为什么:
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 中的任何界面。所以,这是一个通用版本......它是相同的行,除了 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;
}
}
}
}
}
我祈祷我所需要的只是对泛型类型的约束。
除此之外,是否有任何变通方法(例如,一些反射魔法)将任意对象更改为(通用)接口类型?
除此之外,是否有任何方法可以实现相同的 objective(即对实现给定接口的对象的引用的 Unity 序列化,无论这些对象是否是 Unity 内置的- ins 或原始 C#) 以一种干净的方式?
也欢迎反馈/烂番茄关于我的kludge。
我对Unity一无所知,但假设UnityEngine.Object
是一个引用类型,那么你应该可以这样做:
public class SerializableInterfaceReferenceForUnity<TSomeInterface>
where TSomeInterface : class
{
public TSomeInterface obj
{
get
{
if (objIsUnityType) { return unityObj as TSomeInterface; }
else { return rawObj; }
}
}
唯一要记住的是,您将无法使用任何值类型 (struct
) 作为您的 SerializableInterfaceReferenceForUnity
class.