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>();
无需更改 A
或 B
。
为了做这样的事情:
var aObject = A.Me();
Me
需要是静态方法。
- 静态方法没有
this
.
- 如果您 不是 使用静态方法,您有
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" 并不表示该变量是松散类型的或后期绑定的。它只是意味着 编译器确定并分配最合适的类型."
我们有一个抽象 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>();
无需更改 A
或 B
。
为了做这样的事情:
var aObject = A.Me();
Me
需要是静态方法。
- 静态方法没有
this
. - 如果您 不是 使用静态方法,您有
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" 并不表示该变量是松散类型的或后期绑定的。它只是意味着 编译器确定并分配最合适的类型."