步伐密集 易事特再建江蘇充電樁專案

易事特今日發佈公告稱,與江蘇高淳經濟開發區開發總公司就新能源汽車充電樁設備研發製造、IDC整體機房研發製造、智慧微電網等項目投資達成一致意見並簽署協議書。易事特承諾新辦企業固定資產投資總額為6億元人民幣(約新臺幣30億),畝均稅收不低於20萬元(約新臺幣101萬),首期建築面積不低於30000平方米。高淳經濟開發區將供地約120畝,使用年限為50年。   易事特佈局充電樁可謂步伐密集。今年8月13日,易事特與馬鞍山經濟技術開發區管理委員會簽訂了《投資框架協議書》,擬在對方區域內投資建設資料中心、分散式發電設備與系統集成和新能源汽車充電站(樁)項目。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

Jmeter系列(34)- 詳解 Counter 計數器

如果你想從頭學習Jmeter,可以看看這個系列的文章哦

https://www.cnblogs.com/poloyy/category/1746599.html

 

簡單介紹

  • 計數器的作用:循環遞增生成数字
  • 計數器使用 long 來存儲值,因此取值範圍是 -2 ^ 63 2 ^ 63-1 
  • 可以在線程組任意地方添加計數器

 

計數器

 

計數器界面介紹

 

字段介紹

字段 含義
Starting value 初始值,long 整型,默認 0
Increment 每次迭代的遞增值,默認 0,表示不增加
Maximum value 最大值,包含此值
Number format 数字可選格式
Exported Variable Name 引用名稱
Track counter independently for rach user 每個用戶都有一個獨立的計數器
Reset counter on each Thread Group Iteration 每次線程組迭代時計數器將重置為初始值

 

最基礎的栗子

只有計數器的情況下的栗子

線程組結構樹

 

線程組屬性

共有 15 個線程,模擬 15 個用戶

 

計數器

計數器最多循環計數 10 次

 

運行結果

可以看到,因為有 15 個用戶,但計數器最多循環計數 10 次,所以第一輪循環結束後會重頭開始

 

計數器 + 循環控制器的栗子

線程組結構樹

 

線程組屬性

共有 5 個線程,模擬 5 個用戶

 

循環控制器

每個線程運行 3 次

 

計數器

計數器最多循環計數 30 次

 

未勾選【與每用戶獨立的跟蹤計數器】的運行結果

可以看到

  • 因為有 5 個線程,每個線程循環 3 次,一共 15 個請求,所以計數器是循環了 15 次
  • 此時計數器是對所有線程共享的,屬於線程組全局計數器,所以計數器是累計循環了 15 次

 

勾選【與每用戶獨立的跟蹤計數器】的運行結果

可以看到

  • 每個線程運行時,計數器都是從初始值算起的
  • 此時計數器是每個線程獨享的,不再是公共計數器,所以每次有新的線程運行時,都是新的計數器開始循環計數

 

計數器的一些注意事項

使用計數器生成的變量,值的類型為 string,所以有比較之類的操作時,需要帶 “” 操作

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

原子力寄生委員會! 福島輻射污染水問題重重

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

電動車免牌照稅 可望延長至 2018 年

為鼓勵購買低汙染的環保車輛,電動汽車將再延長牌照稅免稅期 3 年。包括電動小客車、巴士與貨車,免徵牌照稅優惠將可持續至 2018 年 1 月 5 日為止。   為基於扶植國內電動車研發製造的需要,立法院財政委員會 12 日將審查由行政院提出的用牌照稅法修正草案,授權給地方政府對以電能為動力的電動汽車,免徵牌照稅優惠期間,可以再延長 3 年。經濟日報指出,這項減稅法案可望趕在立法院本會期結束前完成修法程序,以便接續提供減免。   財政部指出,免徵電動車使用照稅優惠措施自 2012 年 1 月 5 日施行至今,國庫釋出的免稅利益將近新台幣 1,000 萬元,平均每年約為 300 萬元。過去 3 年,申請免稅的電動車由 319 輛成長到 574 輛,減稅金額也從約 200 萬元倍增至近 400 萬元。財政部認為,電動車申請免稅案件逐年增加,代表電動車的使用與購買意願也在上升。  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

mybatis緩存之一級緩存(二)

這篇文章介紹下mybatis的一級緩存的生命周期

一級緩存的產生

一級緩存的產生,並不是看mappper的xml文件的select方法,看下面的例子

mapper.xml

    <select id="getById" resultType="entity.TempEntity">
       select * from  temp where id = #{id}
    </select>

test

    @Test
    public  void testSelectAsUpdate() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        sqlSession.update("dao.Temp03Dao.getById", 1);
        sqlSession.update("dao.Temp03Dao.getById", 1);
    }

執行結果

2020-06-26 17:33:27,899 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:33:27,922 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:33:27,923 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:33:27,923 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)

我們可以看到執行了2次查詢。說明並沒有產生緩存。說明和sqlsession調用的方法是有關係的

只有調用上圖中的方法才會產生一級緩存

一級緩存的銷毀

1.關閉session

這個是根據debug看到的一級緩存的最終結構。下面是整個依賴的類圖

test

 @Test
    public  void test() throws IOException, NoSuchFieldException, IllegalAccessException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity1);

        Field executorField = sqlSession.getClass().getDeclaredField("executor");
        executorField.setAccessible(true);
        CachingExecutor  cachingExecutor = (CachingExecutor) executorField.get(sqlSession);

        Field declaredField = cachingExecutor.getClass().getDeclaredField("delegate");
        declaredField.setAccessible(true);
        SimpleExecutor simpleExecutor  = (SimpleExecutor) declaredField.get(cachingExecutor);

        Field localCacheField = simpleExecutor.getClass().getSuperclass().getDeclaredField("localCache");
        localCacheField.setAccessible(true);
        PerpetualCache perpetualCache = (PerpetualCache) localCacheField.get(simpleExecutor);

        Field cacheField = perpetualCache.getClass().getDeclaredField("cache");
        cacheField.setAccessible(true);
        Map<Object,Object> map= (Map<Object, Object>) cacheField.get(perpetualCache);
        logger.info("緩存關閉前");
        for (Map.Entry<Object,Object> objectObjectEntry:map.entrySet()){
            logger.info(objectObjectEntry.getKey() + "===" + objectObjectEntry.getValue());
        }
        sqlSession.close();
        logger.info("緩存關閉后");

        for (Map.Entry<Object,Object> objectObjectEntry:map.entrySet()){
            logger.info(objectObjectEntry.getKey() + "=" + objectObjectEntry.getValue());
        }
    }

運行結果

2020-06-26 17:38:52,777 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:38:52,801 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:38:52,824 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:38:52,824 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:38:52,825 INFO [TempTest] - 緩存關閉前
2020-06-26 17:38:52,826 INFO [TempTest] - -1654591322:461730790:dao.Temp03Dao.getById:0:2147483647:select * from  temp where id = ?:1:dev===[TempEntity{id=1, value1='11111', value2='aaaaa'}]
2020-06-26 17:38:52,827 INFO [TempTest] - 緩存關閉后

可以看到session關閉后,緩存就不存在了

2.Commit提交

test

    @Test
    public  void testCommit() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity1);
        sqlSession.commit();
        TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity2);
        logger.info(tempEntity1 == tempEntity2);

    }

運行結果

2020-06-26 17:40:40,821 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:40:40,846 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:40:40,862 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:40:40,862 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:40:40,863 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:40:40,863 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:40:40,864 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:40:40,864 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:40:40,864 INFO [TempTest] - false

說明sqlSession.commit時會清空緩存

3.Rollback

test

    @Test
    public  void testRollback() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity1);
        sqlSession.rollback();
        TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity2);
        logger.info(tempEntity1 == tempEntity2);

    }

執行結果

2020-06-26 17:42:23,793 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:42:23,833 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:42:23,843 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:42:23,843 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:42:23,844 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:42:23,844 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:42:23,845 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:42:23,845 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:42:23,845 INFO [TempTest] - false

sqlSession.rollback()也會清空緩存

4.update更新

這裡是在第一次查詢后,緊接着進行update操作。這裏與表無關。就是操作其它表,也會清空緩存。

test

    @Test
    public  void testForUpdate() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity1);
        sqlSession.update("dao.Temp03Dao.updateById", 1);
        TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity2);
        logger.info(tempEntity1 == tempEntity2);

    }

運行結果

2020-06-26 17:45:43,997 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:45:44,034 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:45:44,048 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:45:44,049 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:45:44,049 DEBUG [dao.Temp03Dao.updateById] - ==>  Preparing: update temp set value1 = 'ffffff' where id = ? 
2020-06-26 17:45:44,049 DEBUG [dao.Temp03Dao.updateById] - ==> Parameters: 1(Integer)
2020-06-26 17:45:44,050 DEBUG [dao.Temp03Dao.updateById] - <==    Updates: 1
2020-06-26 17:45:44,051 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:45:44,051 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:45:44,052 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:45:44,053 INFO [TempTest] - TempEntity{id=1, value1='ffffff', value2='aaaaa'}
2020-06-26 17:45:44,053 INFO [TempTest] - false

這裏還是在一個session會話中。記得之前有人給我說只要在一個session會話中,執行update不會清空緩存。這裏的代碼就證明了

5.clearCache 主動清除

test

    @Test
    public  void testClearCatch() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity1);
        sqlSession.clearCache();
        TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1);
        logger.info(tempEntity2);
        logger.info(tempEntity1 == tempEntity2);

    }

運行結果

2020-06-26 17:48:42,085 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:48:42,110 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:48:42,124 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:48:42,124 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:48:42,125 DEBUG [dao.Temp03Dao.getById] - ==>  Preparing: select * from temp where id = ? 
2020-06-26 17:48:42,125 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)
2020-06-26 17:48:42,126 DEBUG [dao.Temp03Dao.getById] - <==      Total: 1
2020-06-26 17:48:42,126 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'}
2020-06-26 17:48:42,126 INFO [TempTest] - false

一級緩存 臟讀問題

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

新能源汽車入北京 改為備案制

在中國的全球新能源汽車大會上,北京市科委新能源與新材料處處長許心超透露,北京市新能源汽車準入方式有所調整,由先前的新能源汽車目錄方式改為備案方式,車型只要備案即可在北京銷售、上牌。   先前規定,按照《北京市示範應用新能源小客車生企業及品目錄》,北京市共有 7 款新能源汽車可在備案之後直接銷售、上牌。而這次許心超表示,按照中央的要求,準入方式也在改變,主要採取備案制,只要備案了就可銷售,政府則加強事後監管。
這意味著所有中國純電動汽車都可以進京銷售、上牌,享受財政補貼,而不再像以前必須要先進入嚴格的北京市新能源汽車目錄。   另一方面,為了讓純電動汽車的使用者迅速找到充電樁,相關部門也在進行改進,一是和百度合作,標注所有充電樁的電子地圖將很快上線;二是印製北京充電樁地圖;三是辦充電體驗周活動,在 2 月 2 日至 6 日,將分 2 次聯合所有北京的汽車企業,做充電實際體驗。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

「寂靜的春天」預言實現了 研究發現新菸鹼類影響水生物和魚群

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

挖角鋰電池廠 A123 傳蘋果電動車將於 2020 年量產

過去幾個月來,蘋果打算進軍終極行動裝置──汽車的傳言甚囂塵上。最新消息更顯示,蘋果正在加緊鞭策研發團隊,希望能在 2020 年產出旗下第一輛電動車。無獨有偶,數小時前才剛洩漏的法院文件顯示,美國汽車鋰離子電池與電池系統廠商 A123 Systems Inc. 控訴蘋果挖角多名重要的工程師,或許蘋果開發電動車是真有其事。   彭博社 20 日引述未具名消息人士報導,蘋果最快 2020 年就會開始量產電動車。一般來說,有經驗的汽車業者想要研發一款全新汽車、通常得花上 5 至 7 年的時間,假如要從零開始、時間更得費上 10 年之久。蘋果設定了如此緊迫的量產時程,凸顯了該公司對汽車領域的強大企圖心。   相較之下,特斯拉(Tesla Motors Inc.)、通用汽車(General Motors Co.)這兩家汽車大廠,則都預定要在 2017 年發表一輛單次充電後可行駛超過 200 英里、售價低於 4 萬美元的電動車。   蘋果的汽車團隊過去幾個月加緊聘人、目前已有 200 人之譜,而最新延攬的員工大多是電池、機器人專才。不過,根據消息人士的說法,倘若汽車的進展不如預期,蘋果仍可能推延開發案、或甚至直接抽手退出。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

C# 9.0 終於來了, Top-level programs 和 Partial Methods 兩大新特性探究

一:背景

1. 講故事

.NET 5 終於在 6月25日 發布了第六個預覽版,隨之而來的是更多的新特性加入到了 C# 9 Preview 中,這個系列也可以繼續往下寫了,廢話不多說,今天來看一下 Top-level programsExtending Partial Methods 兩大新特性。

2. 安裝必備

下載最新的 .net 5 preview 6

下載最新的 Visual Studio 2019 version 16.7 Preview 3.1

二:新特性研究

1. Top-level programs

如果大家玩過 python,應該知道在 xxx.py 中寫一句 print,這程序就能跑起來了,簡單高效又粗暴,很開心的是這特性被帶到了C# 9.0 中。

  • 修改前

using System;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }

  • 修改后

System.Console.WriteLine("Hello World!");

這就有意思了,Main入口函數去哪了? 沒它的話,JIT還怎麼編譯代碼呢? 想知道答案的話用 ILSpy 反編譯看一下就好啦!


.class private auto ansi abstract sealed beforefieldinit $Program
	extends [System.Runtime]System.Object
{
	.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
		01 00 00 00
	)
	// Methods
	.method private hidebysig static 
		void $Main (
			string[] args
		) cil managed 
	{
		// Method begins at RVA 0x2050
		// Code size 18 (0x12)
		.maxstack 8
		.entrypoint

		IL_0000: ldstr "Hello World!"
		IL_0005: call void [System.Console]System.Console::WriteLine(string)
		IL_000a: nop
		IL_000b: call string [System.Console]System.Console::ReadLine()
		IL_0010: pop
		IL_0011: ret
	} // end of method $Program::$Main

} // end of class $Program


從 IL 上看,類變成了 $Program, 入口方法變成了 $Main, 這就好玩了,在我們的印象中入口函數必須是 Main,否則編譯器會給你一個大大的錯誤,你加了一個 $ 符號,那CLR還能認識嗎? 能不能認識我們用 windbg 看一些託管和非託管堆棧,看看有什麼新發現。


0:010> ~0s
ntdll!NtReadFile+0x14:
00007ffe`f8f8aa64 c3              ret
0:000> !dumpstack
OS Thread Id: 0x7278 (0)
Current frame: ntdll!NtReadFile + 0x14
Child-SP         RetAddr          Caller, Callee
0000008551F7E810 00007ffed1e841dc (MethodDesc 00007ffe4020d500 + 0x1c System.Console.ReadLine()), calling 00007ffe400ab090
0000008551F7E840 00007ffe4014244a (MethodDesc 00007ffe401e58f0 + 0x3a $Program.$Main(System.String[])), calling 00007ffe40240f58
0000008551F7E880 00007ffe9fcc8b43 coreclr!CallDescrWorkerInternal + 0x83 [F:\workspace\_work\1\s\src\coreclr\src\vm\amd64\CallDescrWorkerAMD64.asm:101]
0000008551F7E8C0 00007ffe9fbd1e03 coreclr!MethodDescCallSite::CallTargetWorker + 0x263 [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:554], calling coreclr!CallDescrWorkerWithHandler [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:56]
0000008551F7E950 00007ffe9fb8c4e5 coreclr!MethodDesc::IsVoid + 0x21 [F:\workspace\_work\1\s\src\coreclr\src\vm\method.cpp:1098], calling coreclr!MetaSig::IsReturnTypeVoid [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp:5189]
0000008551F7EA00 00007ffe9fb8c4bf coreclr!RunMainInternal + 0x11f [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1488], calling coreclr!MethodDescCallSite::CallTargetWorker [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:266]
0000008551F7EB30 00007ffe9fb8c30a coreclr!RunMain + 0xd2 [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1559], calling coreclr!RunMainInternal [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1459]

從上面堆棧的流程圖看: coreclr!RunMain -> coreclr!MethodDesc -> coreclr!CallDescrWorkerInternal -> $Program.$Main, 確實被調用了,不過有一個重大發現,在 $Program.$Main 調用之前底層的 CLR 讀取了 方法描述符,這就是一個重大突破點,方法描述符在哪裡呢? 可以用 ildasm 去看一下元數據列表。

可以看到,入口函數那裡打上了一個 ENTRYPOINT 標記,這就說明入口函數名其實是可以隨便更改的,只要被 ENTRYPOINT打上標記即可,CoreCLR就能認的出來~~~

2. Partial Methods

我們知道 部分方法 是一個很好的樁函數,而且在 C# 3.0 中就已經實現了,那時候給我們增加了很多限制,如下圖:

翻譯過來就是:

  • 部分方法的簽名必須一致

  • 方法必須返回void

  • 不允許使用訪問修飾符,而且還是隱式私有的。

在 C# 9.0 中放開了對 方法簽名 的所有限制,正如 issue 總結:

這是一個非常好的消息,現在你的部分方法上可以加上各種類型的返回值啦,這裏我舉一個例子:


    class Program
    {
        static void Main(string[] args)
        {
            var person = new Person();

            Console.WriteLine(person.Run("jack"));
        }
    }

    public partial class Person
    {
        public partial string Run(string name);
    }

    public partial class Person
    {
        public partial string Run(string name) => $"{name}:開溜了~";
    }

然後我們用 ILSpy 簡單看看底層怎麼玩的,如下圖可以看到其實就是一個簡單的合成,對吧。

現在我有想法了,如果我不給 Run 方法實現會怎麼樣? 把下面的 partial 類註釋掉看一下。

從報錯信息看,可訪問的修飾符必須要有方法實現,還以為直接編譯的時候抹掉呢。 這就起不到樁函數的作用:-D,不過這個特性還是給了我們更多的可能用的到的應用場景吧。

三:總結

本篇兩個特性還是非常實用的,Top-level programs 讓我們可以寫更少的代碼,甚至拿起 記事本 都可以快捷的編寫類似一次性使用的測試代碼, Partial Methods 特性留給大家補充吧,我基本上算是沒用過 (┬_┬)。

如您有更多問題與我互動,掃描下方進來吧~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

習近平馬克宏聯合聲明 強調巴黎氣候協定不可逆

摘錄自2019年11月6日中央社外電報導

美國本週向聯合國提交退出巴黎氣候協定的通知信函後,中國國家主席習近平和法國總統馬克宏(Emmanuel Macron)今天(6日)共同宣布,堅定支持巴黎氣候協定並強調協定「不可逆」。

法新社報導,儘管有越來越多證據顯示氣候變遷的事實和影響,美國總統川普仍執意退出巴黎氣候協定,世界各國紛紛表達遺憾及關切。

華府4日向聯合國(UN)提交退出巴黎氣候協定(Paris Agreement)的通知信函,讓世界最大經濟體美國成為至今唯一退出這項協定的國家。

根據美國前總統歐巴馬(Barack Obama)談成的這項氣候協定,11月4日是美方最早可以正式提出退出協定的首日。

習近平和馬克宏在北京舉行會談後的聯合聲明說,中法兩國領導人重申「他們堅定支持巴黎氣候協定,他們認為這項協定是不可逆轉的進程,也是針對氣候問題採取強而有力行動時的方針」。

兩人在北京會談後,馬克宏坐在習近平旁邊。當時馬克宏沒有直接指名美國,只說他「對於其他人所做的選擇深感遺憾」。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準