在抽象类中返回具体类型

时间:2016-01-28 11:34:37

标签: c# generics abstract-class

我们有一个抽象类BaseClass(注意泛型arg!),其方法名为me。 我回来了。

如果我们在具体类中使用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);

在某些情况下,由于laze加载等原因,结果不是A类型但是AProxy类型。现在如果我们想要将结果转换为其他内容:我们将获得invalidcastexception,因为实际的结果类型不是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属性,以便我们立即返回具体类型吗?

希望现在很清楚。

5 个答案:

答案 0 :(得分:5)

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

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

}

答案 1 :(得分:3)

您可以在派生类上使用接口:

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

答案 2 :(得分:2)

不幸的是,C#,unlike Javadoes 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提供了一个很好的解决方法。

答案 3 :(得分:0)

为了做这样的事情:

var aObject = A.Me();

Me需要是静态方法。

  1. 静态方法this
  2. 如果您的使用静态方法,则您拥有this - 否则您打算如何调用类方法?您只需要将其转换为正确的类型。
  3. 由于编辑而更新:

    您有以下代码:

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

    现在你在这里期待什么?
    您的a来自A类型 使用var,您无法从Me geter获得多种不同的返回类型。

答案 4 :(得分:0)

问题似乎是使用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;确实会在编译时为A返回一个类型aConcrete,但不会在编辑器中返回。

来自MSDN:&#34;重要的是要理解var关键字并不意味着&#34;变体&#34;并不表示变量是松散类型的,也不是后期绑定的。它只是意味着编译器确定并分配最合适的类型。&#34;