返回抽象类中的具体类型

本文关键字:类型 抽象类 返回 | 更新日期: 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>();

无需更改AB

可以将此属性的返回类型更改为父类的定义

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需要是一个静态方法。

  1. 静态方法没有this
  2. 如果你不使用静态方法,你就有this - 否则你怎么愿意调用类方法?您只需要将其转换为正确的类型。

因编辑而更新:

你有以下代码:

var a = new A();
var aObject = a.Me;

现在你在这里期待什么?
您有来自类型 Aa
通过使用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 关键字并不意味着"变体",也不表示变量是松散类型或后期绑定的。这只是意味着编译器确定并分配最合适的类型