C# 关于“的隐式/显式转换”;作为「;关键词
我正在尝试对一个不幸具有高度单元相互依赖性的项目进行一些单元测试。目前,我们的很多类都使用自定义的UserIdentity对象来确定身份验证,但该对象有很多内部跳转,在尝试测试单个单元功能时,我会尽快避免这些跳转 为了解决其中的一些问题,我尝试创建一个“模拟”版本的这个用户标识,它可以插入一个更严格控制的变量环境 长话短说,我们有一个UserIdentity类,它有几个公共只读属性和一个静态CurrentIdentity(IIdentity)占位符。我可以用一个“mock”IIdentity实现解决几乎所有问题,但当我达到将CurrentIdentity转换为用户身份的程度时,我就遇到了麻烦 这是一个非常直接的方法:C# 关于“的隐式/显式转换”;作为「;关键词,c#,.net,casting,C#,.net,Casting,我正在尝试对一个不幸具有高度单元相互依赖性的项目进行一些单元测试。目前,我们的很多类都使用自定义的UserIdentity对象来确定身份验证,但该对象有很多内部跳转,在尝试测试单个单元功能时,我会尽快避免这些跳转 为了解决其中的一些问题,我尝试创建一个“模拟”版本的这个用户标识,它可以插入一个更严格控制的变量环境 长话短说,我们有一个UserIdentity类,它有几个公共只读属性和一个静态CurrentIdentity(IIdentity)占位符。我可以用一个“mock”IIdentity实现
internal static UserIdentity GetCurrentIdentity()
{
UserIdentity currentIdentity = ApplicationContext.User.Identity as UserIdentity;
return currentIdentity;
}
我已将模拟对象设置为创建UserIdentity类型的成员,然后执行如下操作:
public static implicit operator UserIdentity(MockUserIdentity src)
{
return src.UserIdentity;
}
public static UserIdentity op_Explicit(MockUserIdentity src)
{
return src.UserIdentity;
}
还是这个
public static explicit operator UserIdentity(MockUserIdentity src)
{
return src.UserIdentity;
}
问题是,据我所知,“as”似乎没有在我的模拟对象上调用隐式或显式转换操作。我的问题是(是吗?),我是缺少了一些简单的东西,还是因为(我猜)“as”操作直接指向类继承(我的对象没有这样做…)而不起作用
另外,可能有点离题,但为什么在一个类中不能同时存在相同结果类型的显式和隐式运算符呢?除非我遗漏了一些愚蠢的东西,否则如果我试图同时使用两个转换运算符,编译器会犹豫。我得选一个
更新
好吧,现在我完全糊涂了。也许我有点邋遢,但我试过做直接演员,但我似乎也无法让它发挥作用。我阅读了MSDN中的操作符,示例显示操作符在结果类而不是源类中,但我不确定这是否重要(我在下面的代码中尝试了两个位置)。不管怎样,我试着建立一个简单的测试台,看看我可能做错了什么,但我也不能让它工作…这是我得到的
class Program
{
// Shared Interface
public interface IIdentity { }
// "real" class (not conducive to inheritence)
public class CoreIdentity : IIdentity
{
internal CoreIdentity() { }
// Just in case (if this has to be here, that seems unfortunate)
public static explicit operator CoreIdentity(ExtendedIdentity src)
{
return src.Identity;
}
}
// "mock" class (Wraps core object)
public class ExtendedIdentity : IIdentity
{
public CoreIdentity Identity { get; set; }
public ExtendedIdentity()
{
Identity = new CoreIdentity();
}
// This is where the operator seems like it should belong...
public static explicit operator CoreIdentity(ExtendedIdentity src)
{
return src.Identity;
}
}
// Dummy class to obtain "current core identity"
public class Foo
{
public IIdentity Identity { get; set; }
public CoreIdentity GetCoreIdentity()
{
return (CoreIdentity)Identity;
}
}
static void Main(string[] args)
{
ExtendedIdentity identity = new ExtendedIdentity();
Foo foo = new Foo();
foo.Identity = identity;
CoreIdentity core = foo.GetCoreIdentity();
}
}
但当我调用foo.GetCoreIdentity()时,会引发以下异常:
无法将“ExtendedIdentity”类型的对象强制转换为“CoreIdentity”类型。
我不能用断点捕捉任何一个显式运算符,所以它看起来是在不“尝试”我提供的转换路径的情况下做出这个决定的
我肯定错过了一些明显的东西。我将标识(在Foo中)定义为IIdentity这一事实是否以某种方式阻止了使用实现类型的显式运算符解析强制转换?我觉得这很奇怪
更新(#2)
我觉得我在用所有这些更新来滥发我的帖子(也许我应该在如此兴奋之前把我的行为集中起来:)。无论如何,我修改了我的Foo的GetCoreIdentity方法来做这件事:
public CoreIdentity GetCoreIdentity()
{
ExtendedIdentity exId = Identity as ExtendedIdentity;
if (exId != null)
return (CoreIdentity)exId;
return (CoreIdentity)Identity;
}
并且(在必须清除由于在两个类中都使用该运算符而导致的不明确引用之后),它确实进入了我的显式转换运算符代码,并且它按照预期工作。因此,我猜显式运算符似乎不是多态解析的(这是正确的理解吗?),而且我的属性被类型化为IIdentity而不是ExtendedIdentity这一事实阻止了它调用强制转换逻辑,即使它在被调用时是ExtendedIdentity类型。这让我感到非常奇怪和意外……而且有点不幸
我不想重新编写CurrentIdentity对象的守护者来让它知道我的特殊测试强制转换模拟。我想将“特殊”逻辑封装到模拟本身中,因此这真的让我陷入了一个循环。as不调用转换运算符。见:
使用(强制转换)。那么,为什么不使用显式强制转换呢
// will throw if cast fails
internal static UserIdentity GetCurrentIdentity()
{
UserIdentity currentIdentity = (UserIdentity) ApplicationContext.User.Identity ;
return currentIdentity;
}
这应该会触发显式运算符。您可以先使用
is
进行测试,以使其更安全。正如Ray所述,As
不会调用转换运算符
也就是说,您应该在这种类型的场景中使用显式强制转换
这样,当设置不正确,并且ApplicationContext.User.Identity中的对象不是代码所期望的对象时,您可以获得非常清晰的信息
事实上我有我的身份吗
(在Foo中)以某种方式定义为身份
防止使用
函数的显式算子
实现类型
这里有一个提示:如何定义显式(或隐式)转换运算符?(我知道你知道这一点,因为你已经做到了;我问这个问题是为了说明一点。)
这里有一件非常重要的事情需要认识到。C#设计人员做出了明智的选择,使所有操作符都是静态的。因此,上面定义的显式运算符本质上转化为静态方法调用,如下所示:
public static implicit operator UserIdentity(MockUserIdentity src)
{
return src.UserIdentity;
}
public static UserIdentity op_Explicit(MockUserIdentity src)
{
return src.UserIdentity;
}
现在,我的意思是。在你的问题中让你困惑的行为,因为它在多态性部门似乎失败了,实际上是C#的方法重载解析系统的结果
如果我有两种方法:
void Write(string s) { Console.WriteLine("string"); }
void Write(object o) { Console.WriteLine("object"); }
…然后我有一个程序:
object x = "Hello!";
Write(x);
输出是什么
答案是“object”,因为编译器选择了写(object)
重载,这也是应该选择的Write
不是根据正常多态性由某个派生类型重写的实例方法;它是一个静态方法,带有重载,编译器必须在重载之间做出选择。由于上述代码中的x
被声明为obj类型
public CoreIdentity GetCoreIdentity()
{
ExtendedIdentity exId = Identity as ExtendedIdentity;
if (exId != null)
{
// Since exId is actually declared to be of type ExtendedIdentity,
// the compiler can choose the operator overload accepting
// an ExtendedIdentity parameter -- so this will work.
return (CoreIdentity)exId;
}
return (CoreIdentity)Identity;
}