Return 抽象的具体类型 class

Return concrete type in abstract class

我们有一个抽象 class BaseClass(注意泛型 arg!),其中包含一个名为 me 的方法。 我 return 就是这个。

如果我们在具体的 classes 中使用 Me,我们将得到一个 return 类型的对象。 然后我们必须将 Me 的结果转换为我们最初使用的类型。

我们如何实现 Me return 的实际类型?在此示例中键入 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 属性 以便我们立即 return 具体类型?

希望现在天气晴朗了。

您可以将此 属性 的 return 类型更改为父 class

的定义
public abstract class BaseClass<TIdentifier> 
{
     public virtual BaseClass<TIdentifier> Me{ get { return this; } }
}

如果您想 return 完全相同 class 您可以通过在泛型类型参数中添加结果类型来解决一些问题

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>
{

}

您可以在派生的 类:

上使用接口
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

为了做这样的事情:

var aObject = A.Me();

Me 需要是静态方法。

  1. 静态方法没有 this.
  2. 如果您 不是 使用静态方法,您有 this - 否则您愿意如何调用 class 方法?您只需将其转换为正确的类型即可。

由于编辑而更新:

你有这个代码:

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

现在你在这里期待什么?
您有 a 类型 A.
通过使用 var,您不能从 Me geter 获得多个不同的 return 类型。

不幸的是,C#,unlike Java, does not support return type covariance。否则你可以像这样重写子类中的 属性 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 对变量的隐式定义。在这种情况下使用 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 等方法似乎是您唯一的希望。

更新: 您可以参考 this 以查看可以对 Type 对象进行的调用类型。看起来您将不得不更加动态地执行此操作以实现所需的功能。如果试图隐式地执行此操作,则在编译之前将无法正确定义该对象。

var aConcrete = a.Me; 在您的代码中确实会 return 在编译时为 aConcrete 生成类型 A,但在编辑器中不会。

From MSDN: "It is important to understand that the var keyword does not mean "variant" 并不表示该变量是松散类型的或后期绑定的。它只是意味着 编译器确定并分配最合适的类型."