2016-01-28 60 views
5

我们有一个抽象类BaseClass(注意泛型arg!)和一个叫做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的,由于懒散加载等。现在,如果我们想投结果到别的东西:我们将得到一个invalidcastexception,因为结果的实际类型不是A,而是AProxy。这种类型不能铸造。我们只能将A型转换为另一种类型。

解决此问题的方法在此处描述:http://sessionfactory.blogspot.be/2010/08/hacking-lazy-loaded-inheritance.html。这就是在上面的例子中我财产进来

因此,要获得A类的结果,而不是类型的AProxy我们现在要做到这一点:

var result = (A)Session.Get<A>(idToLookUp).Me; 

报告中,我们要投我回如果我们想要读取并了解结果的属性,请键入A.

我的问题:我们可以摆脱铸造和调整我的属性,所以我们立即返回具体类型?

希望现在很清楚。

+1

为什么你需要这样做?你已经可以赋值如下:'object a = new A();'因为所有类的基类都是'System.Object'。 – toadflakz

+0

不要搜索原因。这是一个基于我们公司代码的基础示例。原因更复杂:nhibernate bug:请参阅http://sessionfactory.blogspot.be/2010/08/hacking-lazy-loaded-inheritance.html –

+0

我很难理解你的代码..你正在尝试通过调用方法'A.Me()'来获取属性'Me'?这本身并不起作用,首先你不能称它为一种方法,其次它不是静态的,所以'A.Me'也不行。 – mike

回答

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>(); 

没有改变A或要求B

+0

固定 - 指定为类的TReturnType。 – toadflakz

+0

根据你的建议,我实施了一个解决方案。我已经添加了一个接口到BaseClass,所以我不必将TIdentifier传递给我的扩展方法。所以现在我只能说var result = Session.Get (idToLookUp).As (); –

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

} 
+0

恐怕这是最接近你可以得到 – slawekwin

+0

这将返回基类的类型,而不是A的返回类型。 –

+0

这也是一个很多人可能的解决方案。这是一个正确的工作。但是对于我们的具体情况:我们不能/不可以编辑A或B,所以我们不能在通用类型参数中添加结果类型,因为我们必须编辑A和B.我给了你一个赞成票,因为这对于一些有同样问题的人也是一个很好的工作建议 –

0

为了做这样的事情:

var aObject = A.Me(); 

Me将需要一个静态方法。

  1. 静态方法具有this
  2. 如果你的不是使用静态方法,你有this - 否则你如何愿意调用类方法?你只需要把它转换成正确的类型。

更新由于编辑:

你有这样的代码:

​​

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

+0

我的问题有一些错别字和缺点。我已经更新了它,所以你的答案不再适用。但是,谢谢;-) –

+0

@TomB。 - 我更新了一个我不知道你想达到什么。 –

+0

我已经添加了一些有关该案例的解释,希望能够更清楚地了解为什么 –

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# 
} 

米哈伊尔Neofitov虽然提供了一个很好的解决方法。

+0

感谢您的解释。不幸的是,我们不能/不可以改变A或B,因此压倒性的做法可能无法完成。不过,我给了你一个赞成票,因为这也可能是一些人在这个问题上的正确解决方案。 –

+0

谢谢!要清楚的是,这不会在C#中工作,它只是这个*如何完成的一个例子,*如果C#语言支持返回类型协方差。 – proskor

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;在您的代码中确实会在编译时为aConcrete返回一个类型A,但不在编辑器中。

MSDN:变种‘并不表示这个变量是弱类型,或后期绑定它只是意味着编译器确定和分配“明白var关键字并不意味着它是非常重要的。’最合适的类型“。