转换和 As 运算符分别产生转换对象和空引用
Casting and As operator resulting in the casted object and a null reference respectively
这个问题几乎纯粹是为了学习目的。使用的环境是Unity 3D引擎。
我一直在使用 C# 中的 RealProxy 和 MarhalByRefObject classes 来装饰我的一个 classes。具体来说,我使用以下构造函数创建了一个通用代理 class。我正在装饰的 class 也有一个 SerializableAttribute,以及继承自 MarshalByRefObject。
public DynamicProxy(T decorated) : base(typeof(T))
{
}
获取装饰对象,最简单的代码(不带装饰)如下
ClassA toDecorate = new ClassA();
DynamicProxy proxy = new DynamicProxy<ClassA>(toDecorate);
Debug.Log(proxy.GetTransparentProxy() as ClassA);
Debug.Log((ClassA)proxy.GetTransparentProxy());
这就是它变得奇怪的地方。我通过反射检查了类型,确实和我要装饰的对象是同一个类型。但是,令人困惑的部分是,当我正常转换 (ClassA) 时,我得到了对装饰对象的引用,而当我使用 as 运算符时,返回了空引用。
我在测试 Unity v.2019.1.8f1 的构建时发现了这种行为。我使用的脚本运行时版本和 API 都是 .NET 4.x 的等价物。
如果有人有类似的问题,我想听听他们的意见,因为转换和作为操作员的行为不同不应该发生,并且可能会导致大量的时间和精力损失。我并不是真的在寻求解决方案,而是可能比我有更好的想法或遇到过类似问题的人的意见。
注意 :如果我只是做
就不会发生这种行为
ClassA t = new ClassA();
object o = t;
Debug.Log(o as ClassA);
Debug.Log((ClassA)o);
EDIT :经过进一步调查,我注意到 as 运算符本质上是这样做的
E is T ? (T)(E) : (T)null
发生的事情是 is 运算符 returns 为假。
在此处提供重现问题所需的全部代码。
public class HelloThere: MarshalByRefObject
{
public void DoStuff()
{
//Do some stuff here
Debug.Log("Doing some stuff");
}
}
public class Proxy<T> : System.Runtime.Remoting.Proxies.RealProxy
{
private T _decorated;
public Proxy(T decorated): base(typeof(T))
{
_decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
//Do Stuff Before Function
//Call Function
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as System.Reflection.MethodInfo;
try
{
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
return new ReturnMessage(
result, null, 0, methodCall.LogicalCallContext, methodCall);
//Do Stuff After function
}
catch (Exception e)
{
return new ReturnMessage(e, methodCall);
}
}
}
此外,代码检查每个"casting" returns:
Proxy<HelloThere> proxy = new Proxy<HelloThere>(new HelloThere());
Debug.Log(proxy.GetTransparentProxy() as HelloThere);
Debug.Log((HelloThere)proxy.GetTransparentProxy());
问题似乎源于 Unity 3D 引擎本身,特别是它使用 Mono 的变体而不是 .NET。产生这个bug的版本是Unity v. 2019.1.8f1。它不存在于 Unity 2017.x 版本中。正如预期的那样,它也没有出现在由标准 .NET 开发的应用程序中。
这个问题几乎纯粹是为了学习目的。使用的环境是Unity 3D引擎。
我一直在使用 C# 中的 RealProxy 和 MarhalByRefObject classes 来装饰我的一个 classes。具体来说,我使用以下构造函数创建了一个通用代理 class。我正在装饰的 class 也有一个 SerializableAttribute,以及继承自 MarshalByRefObject。
public DynamicProxy(T decorated) : base(typeof(T))
{
}
获取装饰对象,最简单的代码(不带装饰)如下
ClassA toDecorate = new ClassA();
DynamicProxy proxy = new DynamicProxy<ClassA>(toDecorate);
Debug.Log(proxy.GetTransparentProxy() as ClassA);
Debug.Log((ClassA)proxy.GetTransparentProxy());
这就是它变得奇怪的地方。我通过反射检查了类型,确实和我要装饰的对象是同一个类型。但是,令人困惑的部分是,当我正常转换 (ClassA) 时,我得到了对装饰对象的引用,而当我使用 as 运算符时,返回了空引用。
我在测试 Unity v.2019.1.8f1 的构建时发现了这种行为。我使用的脚本运行时版本和 API 都是 .NET 4.x 的等价物。
如果有人有类似的问题,我想听听他们的意见,因为转换和作为操作员的行为不同不应该发生,并且可能会导致大量的时间和精力损失。我并不是真的在寻求解决方案,而是可能比我有更好的想法或遇到过类似问题的人的意见。
注意 :如果我只是做
就不会发生这种行为ClassA t = new ClassA();
object o = t;
Debug.Log(o as ClassA);
Debug.Log((ClassA)o);
EDIT :经过进一步调查,我注意到 as 运算符本质上是这样做的
E is T ? (T)(E) : (T)null
发生的事情是 is 运算符 returns 为假。
在此处提供重现问题所需的全部代码。
public class HelloThere: MarshalByRefObject
{
public void DoStuff()
{
//Do some stuff here
Debug.Log("Doing some stuff");
}
}
public class Proxy<T> : System.Runtime.Remoting.Proxies.RealProxy
{
private T _decorated;
public Proxy(T decorated): base(typeof(T))
{
_decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
//Do Stuff Before Function
//Call Function
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as System.Reflection.MethodInfo;
try
{
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
return new ReturnMessage(
result, null, 0, methodCall.LogicalCallContext, methodCall);
//Do Stuff After function
}
catch (Exception e)
{
return new ReturnMessage(e, methodCall);
}
}
}
此外,代码检查每个"casting" returns:
Proxy<HelloThere> proxy = new Proxy<HelloThere>(new HelloThere());
Debug.Log(proxy.GetTransparentProxy() as HelloThere);
Debug.Log((HelloThere)proxy.GetTransparentProxy());
问题似乎源于 Unity 3D 引擎本身,特别是它使用 Mono 的变体而不是 .NET。产生这个bug的版本是Unity v. 2019.1.8f1。它不存在于 Unity 2017.x 版本中。正如预期的那样,它也没有出现在由标准 .NET 开发的应用程序中。