返回抽象类中的具体类型
本文关键字:类型 抽象类 返回 | 更新日期: 2023-09-27 18:32:12
我们有一个名为me的方法的抽象类BaseClass(注意泛型arg!)。我返回这个。
如果我们在具体类中使用 Me,我们将得到一个返回类型对象。然后,我们必须将 Me 的结果转换为我们最初正在使用的类型。
我们如何实现 Me 返回此的实际类型?在此示例中,键入 A?
public abstract class BaseClass<TIdentifier>{
public virtual object Me{ get { return this; } }
}
public class A: BaseClass<long>
{
}
public class B: BaseClass<long>
{
}
public class controller{
public void SomeMethod(){
var a = new A();
var b = new B();
var aObject = a.Me; // this will be of type object
var aObjectCasted = (A)aObject; // cast to original
// How I want it
var aConcrete = a.Me; // this returns type a
}
}
更新
因为有些人真的,绝望地(眨眼:-))希望了解我实际上想做什么。
使用NHibernate,我们正在这样做:
var result = Session.Get<A>(idToLookUp);
在某些情况下,由于延迟加载等原因,结果不是 A 型,而是 AProxy 型。现在,如果我们想将结果转换为其他内容:我们将得到一个无效的广播异常,因为结果的实际类型不是 A 而是 AProxy。而且这种类型不能被铸造。我们只能将类型 A 转换为另一种类型。
此处介绍了解决此问题的方法:http://sessionfactory.blogspot.be/2010/08/hacking-lazy-loaded-inheritance.html。这就是上面示例中的 Me 属性的用武之地。
因此,要获得 A 类型而不是 AProxy 类型的结果,我们现在必须这样做:
var result = (A)Session.Get<A>(idToLookUp).Me;
请注意,如果我们想阅读并了解结果的属性,我们必须将我转换回类型 A。
我的问题:我们是否可以摆脱铸件并调整 Me 属性,以便我们立即返回混凝土类型?
希望现在清楚了。
您可以在派生类上使用接口:
public interface IStrongTypedMe<T>
{
T Me();
}
派生类将变为:
public class A: BaseClass<long>, IStrongTypedMe<A>
{
public new A Me()
{
return base.Me() as A;
}
}
当然,这是假设您可以更改A
。
更新:
我现在明白这个问题了(现在才有时间阅读链接的文章)。
尝试使用扩展方法为您进行转换,如下所示:
public static TReturnType As<TReturnType,TIdentifier>(this BaseClass<TIdentifier> proxyObject)
where TReturnType : class
{
return proxyObject.Me as TReturnType;
}
你会像这样使用它:
var result = Session.Get<A>(idToLookUp).As<A,long>();
无需更改A
或B
。
可以将此属性的返回类型更改为父类的定义
public abstract class BaseClass<TIdentifier>
{
public virtual BaseClass<TIdentifier> Me{ get { return this; } }
}
如果要返回完全相同的类,可以通过在泛型类型参数中添加结果类型来做一些解决方法
public abstract class BaseClass<TIdentifier, TMe>
where TMe : BaseClass<TIdentifier, TMe>, new()
{
public virtual TMe Me { get { return (TMe)this; } }
}
public class A : BaseClass<long, A>
{
}
不幸的是,与 Java 不同,C# 不支持返回类型协方差。否则,您可以像这样覆盖子类中的属性Me
以获得所需的内容:
public abstract class BaseClass<TIdentifier> {
public virtual object Me { get { return this; } }
}
public class A: BaseClass<long>
{
public override A Me { get { return this; } } // wont work in C#
}
public class B: BaseClass<long>
{
public override B Me { get { return this; } } // wont work in C#
}
不过,米哈伊尔·尼奥菲托夫(Mikhail Neofitov)提供了一个很好的解决方法。
为了做这样的事情:
var aObject = A.Me();
Me
需要是一个静态方法。
- 静态方法没有
this
。 - 如果你不使用静态方法,你就有
this
- 否则你怎么愿意调用类方法?您只需要将其转换为正确的类型。
因编辑而更新:
你有以下代码:
var a = new A();
var aObject = a.Me;
现在你在这里期待什么?
您有来自类型 A
的a
。
通过使用var
不能从Me
获取器获得多个不同的返回类型。
问题似乎是使用 var
对变量的隐式定义。在这种情况下使用 var
时,编译器无法在编辑器中确定aObject
的正确类型。因此,以以下代码为例:
public abstract class BaseClass<TIdentifier>
{
public virtual object Me {get {return this;} }
}
public class A : BaseClass<TIdentifier>
{
public int X
{
get {return 1;}
}
}
public class B : BaseClass<TIdentifier>
{
}
public class controller{
public void SomeMethod(){
var a = new A();
var b = new B();
var aObject = a.Me;
var aObjectCasted = (A)aObject;
// the environment cannot determine the correct type for aObject
// without compiling and running. At this time in the editor,
// this will be recognized as a type object. It will not
// understand aObject.X and will not compile
Console.WriteLine(aObject.X);
// During run-time, this will work. aObject will be defined as type A
Console.WriteLine(aObject.GetType().GetProperty("X").GetValue(aObject));
// this will output A for the type
Console.WriteLine(aObject.GetType());
}
}
如果无法修改 A 和 B,在隐式定义的变量上使用 GetProperty、GetMethod 等方法似乎是您唯一的希望。
更新:您可以引用它来查看可以对Type
对象进行的调用类型。似乎您必须更动态地执行此操作,以实现所需的功能。如果尝试隐式执行此操作,则在编译之前将无法正确定义对象。
代码中的var aConcrete = a.Me;
确实会在编译时返回 Yield for aConcrete
的类型A
,但不会在编辑器中返回。
来自 MSDN:"重要的是要了解 var 关键字并不意味着"变体",也不表示变量是松散类型或后期绑定的。这只是意味着编译器确定并分配最合适的类型。