我们有一个抽象类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属性,以便我们立即返回具体类型吗?
希望现在很清楚。
答案 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>();
无需更改A
或B
。
答案 2 :(得分:2)
不幸的是,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提供了一个很好的解决方法。
答案 3 :(得分:0)
为了做这样的事情:
var aObject = A.Me();
Me
需要是静态方法。
this
。this
- 否则您打算如何调用类方法?您只需要将其转换为正确的类型。由于编辑而更新:
您有以下代码:
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;