据我所知,让sealed
课程在VTable中找不到,或者我错了?如果我创建一个类sealed
,这是否意味着类层次结构中的所有虚方法也都标记为public class A {
protected virtual void M() { ........ }
protected virtual void O() { ........ }
}
public sealed class B : A {
// I guess I can make this private for sealed class
private override void M() { ........ }
// Is this method automatically sealed? In the meaning that it doesn't have to look in VTable and can be called directly?
// Also what about O() can it be called directly too, without VTable?
}
?
例如:
JSONArray posts = response.optJSONArray(ServerResponseStorage.s_szDEAL_ARRAY);// GETTING DEAL LIST
for (int i = 0; i < posts.length(); i++) {
try {
JSONObject post = posts.getJSONObject(i);// GETTING DEAL AT POSITION AT I
m_VcomData = new CVcomStorage();// object create of DealAppdatastorage
m_VcomData.setmDealTitle(post.getString(ServerResponseStorage.s_szDEAL_NAME));//getting deal name
m_VcomData.setmDealCode(post.getString(ServerResponseStorage.s_szDEAL_CODE));// getting deal code
m_VcomData.setmDealValue(post.getString(ServerResponseStorage.s_szDEAL_VAlUE));
m_VcomData.setmDescription(post.getString(ServerResponseStorage.s_szDEAL_DETAILS));
m_VcomData.setmDealActionUrl(post.getString(ServerResponseStorage.s_szDEAL_ACTION_URL));
String logo = post.getString(ServerResponseStorage.s_szDEAL_LOGO);
m_VcomData.setmIcon(imgPath + logo);
if (BuildConfig.klogInfo)
Log.d(m_kTAG, "Logo Path::" + item.getS_szicon());
if (BuildConfig.kMonkeyInfo)
Log.i("Monkey", "Logo Path::" + item.getS_szicon());
if (!s_VcomDataSet.contains(item)) {
s_VcomDataSet.add(m_VcomData);
m_VcomAdpter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
}
}
m_VcomAdpter = new CVcomAdapter(HomeScreenActivity.this, s_VcomDataSet);
mVcomListview.setAdapter(m_VcomAdpter);
答案 0 :(得分:2)
&#34;我想我可以将这个私密用于密封课程&#34;
您无法在继承层次结构中更改访问修饰符。这意味着如果方法在基类中为public
,则无法在派生类中使其成为private
或internal
或protected
。只有在将方法声明为new
时才能更改修饰符:
private new void M() { ........ }
据我所知,制作类密封摆脱了VTable中的查找 我错了吗?
密封类是层次结构中的最后一个,因为您无法继承它。如果此sealed
类覆盖基类中的某些方法,则虚拟表可与sealed
类一起使用。
如果我让一个类密封,这意味着所有的虚拟方法 类层次结构也标记为密封?
您可以看到IL代码:
.method family hidebysig virtual // method is not marked as sealed
instance void M () cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ret value
}
方法未标记为sealed
。即使您明确将此方法标记为sealed
,您也将获得相同的IL代码。
此外,没有理由在sealed
课程中将方法标记为sealed
。如果课程为sealed
,您无法继承,那么您就无法继承它的方法。
关于虚拟表 - 如果方法覆盖并且您从虚拟表中删除它,则永远不能在继承层次结构中使用它,因此,没有理由重写方法并且永远不会在继承层次结构中使用它。
答案 1 :(得分:2)
首先要注意的是,C#通常会对引用类型上的任何实例方法进行虚拟调用,即使该方法不是虚拟的。这是因为有一个C#规则,在一个不是.NET规则的空引用上调用方法是非法的(如果你在一个空引用上调用一个方法而且该方法没有&#,则在原始CIL中) 39; t本身访问一个字段或虚方法,它工作正常)并使用callvirt
是一种廉价的方法来强制执行该规则。
call
而不是callvirt
,在某些情况下,显然引用不是空的。特别是对于obj?.SomeMethod()
,因为?.
表示已经进行了空检查,如果SomeMethod()
不是虚拟的,则会将其编译为call
。这只发生在?.
,因为编译?.
的代码可以进行检查,而if (obj != null){obj.SomeMethod();}
不会发生这种情况,因为编译.
的代码不会发生。{1}}我知道它正在进行空检查。 所涉及的逻辑非常本地化。
在CIL级别可以跳过虚拟表查找虚拟方法。这就是base
调用工作的方式;编译为call
基于方法的实现而不是callvirt
。通过构造obj?.SomeMethod()
中的扩展,其中SomeMethod
是虚拟的并且是密封的(无论是单独的还是因为obj
的类型被密封),理论上可以将其编译为{{1}到派生类型最多的实现。虽然声明类型和密封类型之间的层次结构中的类添加或删除覆盖,但仍需要进行一些额外的检查以确保它仍能正常工作。它需要一些全局的层次结构知识(并保证知识不会发生变化,这意味着当前正在编译的程序集中的所有类型)才能使优化变得安全。收益很小。并且在大多数情况下仍然无法使用,原因与call
在大多数情况下甚至在非虚拟呼叫中使用的原因相同。
我不认为callvirt
会影响编译器如何生成呼叫,而且它在大多数情况下肯定不会影响它。
抖动可以自由地应用更多的知识,但是如果有的话,差异会非常小。我当然建议您将自己知道的课程标记为sealed
,并且如果抖动使用了那些,那么这很好,但我推荐的主要原因它不是表现而是正确。如果你某个地方试图覆盖你标记为sealed
的类,那么要么A.你刚刚改变了设计,并且知道你必须删除sealed
(。 5秒钟可以删除它)或B.你已经在一个地方做过一些事情,你确信你不会在另一个地方。暂时重新考虑是件好事。
如果我使类密封,这是否意味着类层次结构中的所有虚方法也都标记为密封?
它们被认为是密封的,就像明确标记为密封一样。
答案 2 :(得分:0)
密封意味着您无法继承或覆盖它。如果你不能继承B类,你就无法重写方法M. 至于查找,我不认为你保存它。在你的示例中,调用方法O必须从类A中查找方法并调用它。这是通过vtable进行的。
答案 3 :(得分:0)
使类或方法密封将无效,对B.M()
的任何调用都将是虚拟的。
如果我不得不打赌为什么会这样,我会说它因为M()
在A
中声明,覆盖它不会使该方法“属于”B
如果您检查生成的代码的IL
,您将看到相关指令为callvirt instance string namespace.A::M()
,因此即使密封B
,呼叫也必须是虚拟的。