c#泛型

泛型

泛型是什么丐一?

即通過(guò)參數(shù)化類型來(lái)實(shí)現(xiàn)在同一份代碼上操作多種數(shù)據(jù)類型藻糖。
泛型可以定義類型安全類,而不會(huì)損害類型安全库车、性能或工作效率巨柒。

泛型怎么寫(xiě)?

泛型類

class MyClass<T>
{
    //.............
}

泛型方法

public void MyMethod<T>()
{
    //.............
}

泛型接口

 interface MyInterface<T>
{
    //.............
}

泛型結(jié)構(gòu)

 struct MyStruct<T>
{
    //.............
}

相對(duì)于C#中的類的聲明等語(yǔ)法柠衍,其實(shí)泛型只是多加了一個(gè)類型參數(shù)用來(lái)表示不同類型而已洋满。添加的方式也就是在類、方法等名稱后面加 <T>珍坊。

泛型的使用

對(duì)于泛型的使用牺勾,總結(jié)成一句話就是,跟普通類的使用是幾乎一樣的阵漏,只是在使用過(guò)的時(shí)候需要將類型參數(shù)確定為明確的類型驻民。
泛型就是一個(gè) <T> ,在使用時(shí)將 T 換成確定的類型履怯。

泛型的優(yōu)點(diǎn)

性能

泛型 的一個(gè)優(yōu)點(diǎn)是性能回还。
對(duì)值類型使用 非泛型集合類 在把值類型轉(zhuǎn)換為引用類型,和把引用類型轉(zhuǎn)換為值類型時(shí)需要進(jìn)行裝箱和拆箱操作叹洲。
裝箱拆箱鏈接柠硕。
值存儲(chǔ)在棧上,引用存儲(chǔ)在堆上疹味。
泛型在使用時(shí)定義具體的類型仅叫,避免裝箱拆箱操作帜篇。

類型安全

泛型類型需要在使用時(shí)指定糙捺,只能使用泛型指定的類型,編譯器會(huì)在編譯前檢測(cè)笙隙,提前發(fā)現(xiàn)錯(cuò)誤洪灯。

二級(jí)制代碼重用

泛型可以更好的重用二級(jí)制代碼。泛型類可以定義一次竟痰,并且享有許多不同的類型實(shí)例化签钩。

代碼擴(kuò)展

泛型類的定義會(huì)放在程序集中掏呼,所以使用特定類型實(shí)例化泛型類不會(huì)在IL代碼中重復(fù)這些類。
編譯器將泛型類編譯為本地代碼后會(huì)給每一個(gè)值創(chuàng)建一個(gè)新類铅檩,引用類型共享一個(gè)本地類的所有實(shí)現(xiàn)代碼憎夷。
因?yàn)橐妙愋偷姆盒皖悓?shí)例化只需要4個(gè)字節(jié)內(nèi)存地址,就可以引用一個(gè)引用類型昧旨。
而對(duì)于值類型的存在于泛型類實(shí)例化內(nèi)存中拾给,每個(gè)值類型對(duì)內(nèi)存的要求不同,所以要為每一個(gè)類創(chuàng)建一個(gè)新類兔沃。
引用類型大小確定蒋得,有限,所以引用類型共享代碼乒疏。值類型大小不固定额衙,每個(gè)值類型的實(shí)例化都會(huì)創(chuàng)建新類。

命名約定

  • 泛型類型使用字母T作為前綴怕吴。
  • 如果沒(méi)有特殊要求窍侧,泛型類型允許使用任意類型代替,且只使用了一個(gè)泛型類型械哟,就可以用字符T作為泛型類型的名稱疏之。
  • 如果泛型類型有特定的要求,或者使用了兩個(gè)或多個(gè)泛型類型暇咆,就應(yīng)該給泛型類型使用描述性名稱锋爪。
using System;
using static System.Console;

namespace ConsoleApp22
{
    class Program
    {
        public class MyClass<T1,T2>
        {
            public T1 X1;
            public T2 X2;
        }
        static void Main(string[] args)
        {
            MyClass<int,string> s = new MyClass<int,string>();
            s.X1 = 100;
            s.X2 = "ASD";
            WriteLine(s.X1);
            WriteLine(s.X2);
            ReadKey();
        }
    }
}

描述性名稱并沒(méi)有具體含義,但是要盡量表明其期望的含義爸业,正常應(yīng)該寫(xiě)為Tint,Tstring

泛型(Generic) 允許您延遲編寫(xiě)類或方法中的編程元素的數(shù)據(jù)類型的規(guī)范其骄,直到實(shí)際在程序中使用它的時(shí)候。換句話說(shuō)扯旷,泛型允許編寫(xiě)一個(gè)可以與任何數(shù)據(jù)類型一起工作的類或方法拯爽。

可以通過(guò)數(shù)據(jù)類型的替代參數(shù)編寫(xiě)類或方法的規(guī)范。當(dāng)編譯器遇到類的構(gòu)造函數(shù)或方法的函數(shù)調(diào)用時(shí)钧忽,它會(huì)生成代碼來(lái)處理指定的數(shù)據(jù)類型毯炮。

泛型 可以創(chuàng)建獨(dú)立于被包含類型的類和方法,我們不必給不同的類型編寫(xiě)許多相同的方法或類耸黑,只創(chuàng)建一個(gè)方法或類即可桃煎。
另一個(gè)減少代碼的選項(xiàng)是使用object類,但使用派生自object類的類型進(jìn)行傳遞不是類型安全的大刊。
泛型類 使用 泛型類型 为迈,并且可以根據(jù)特定的類型替換泛型類型,保證了安全性。
如果這個(gè) 泛型 不支持 泛型類 葫辐,編譯器就會(huì)出現(xiàn)錯(cuò)誤搜锰。
泛型 不局限于類,還有用于接口和方法的 泛型耿战。以及用于委托的泛型
委托的泛型鏈接

泛型類

創(chuàng)建泛型類

首先介紹一個(gè)一般的蛋叼,非泛型的簡(jiǎn)化鏈表類,它可以包含任意多的對(duì)象剂陡,以后再把這個(gè)類轉(zhuǎn)化為泛型類鸦列。
在鏈表中,一個(gè)元素引用下一個(gè)元素鹏倘。

image.png

先創(chuàng)建一個(gè)類薯嗤,這部分可以直接看C#實(shí)現(xiàn)鏈表
類中包含鏈表需要的元素。

        public class LinkedListNode
        {
            public LinkedListNode(object value)
            {
                Value = value;
            }
            public object Value { get; set; }//值
            public LinkedListNode Next { get; internal set; }//指向下一個(gè)
            public LinkedListNode Prev { get; internal set; }//指向上一個(gè)
        }

然后實(shí)現(xiàn)具體的鏈表纤泵。

public class LinkedList : IEnumerable//IEnumerable 是 .NET 的接口骆姐,用于實(shí)現(xiàn)迭代
        {
            public LinkedListNode First { get; set; }//鏈表頭
            public LinkedListNode Last { get; set; }//鏈表尾

            public LinkedListNode AddLast(object node)//創(chuàng)建鏈表
            {
                var newNode = new LinkedListNode(node);//對(duì)鏈表數(shù)量化
                if (First == null)//如果頭為空
                {
                    First = newNode;//讓鏈表頭為新鏈表
                    Last = First;//鏈表頭和鏈表尾相等
                }
                else//如果鏈表頭部位空
                {
                    Last.Next = newNode;//尾鏈表的下一個(gè)元素為新鏈表
                    Last = newNode;//尾鏈表尾新鏈表
                }
                return newNode;//返回鏈表
            }
            public IEnumerator GetEnumerator()//迭代方法獲取鏈表
            {
                LinkedListNode current = First;//獲取鏈表頭
                while (current != null)//當(dāng)前鏈表不為空
                {
                    yield return current.Value;//迭代返回鏈表的下一個(gè)元素
                    current = current.Next;//當(dāng)前元素為下一個(gè)元素
                }
            }

實(shí)現(xiàn)鏈表頭尾,擴(kuò)展鏈表捏题,鏈表遍歷通過(guò) 枚舉器 詳情見(jiàn) c#數(shù)組和元組
然后就可以對(duì)鏈表進(jìn)行操作玻褪,

      var list1 = new LinkedList();
      list1.AddLast(2);
      list1.AddLast(4.78);
       list1.AddLast("6");

      foreach (var i in list1)
      {
        WriteLine(i);
      }

接下來(lái)我們創(chuàng)建泛型類版本的鏈表。

using System;
using System.Collections;
using System.Collections.Generic;
using static System.Console;

namespace ConsoleApp22
{
    class Program
    {
        public class LinkedListNode<T>//定義一個(gè)鏈表泛型類
        {
            public LinkedListNode(T value)//泛型類的構(gòu)造函數(shù)
            {
                Value = value;
            }

            public T Value { get; }//只讀字段鏈表值
            public LinkedListNode<T> Next { get; internal set; }//指向下一個(gè)元素指針
            public LinkedListNode<T> Prev { get; internal set; }//指向上一個(gè)元素指針
        }

        public class LinkedList<T> : IEnumerable<T>//鏈表具體實(shí)現(xiàn)
        {
            public LinkedListNode<T> First { get; private set; }//鏈表類型的鏈表頭
            public LinkedListNode<T> Last { get; private set; }//鏈表類型的鏈表尾

            public LinkedListNode<T> AddLast(T node)//鏈表方法公荧,返回一個(gè)鏈表
            {
                var newNode = new LinkedListNode<T>(node);//對(duì)鏈表進(jìn)行實(shí)例化
                if (First == null)//通過(guò)頭結(jié)點(diǎn)為空
                {
                    First = newNode;//頭結(jié)點(diǎn)為鏈表
                    Last = First;//尾結(jié)點(diǎn)就是頭結(jié)點(diǎn)
                }
                else//如果頭結(jié)點(diǎn)不為空
                {
                    Last.Next = newNode;//尾結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)為新傳入的結(jié)點(diǎn)
                    Last = newNode;//尾結(jié)點(diǎn)為這個(gè)新鏈表
                }
                return newNode;//返回新列表
            }

            public IEnumerator<T> GetEnumerator()//對(duì)鏈表遍歷方法带射,返回一個(gè)可迭代泛型集合
            {
                LinkedListNode<T> current = First;//當(dāng)前指針獲取頭結(jié)點(diǎn)

                while (current != null)//如果結(jié)點(diǎn)存在
                {
                    yield return current.Value;//迭代返回當(dāng)前結(jié)點(diǎn)的值
                    current = current.Next;//當(dāng)前結(jié)點(diǎn)轉(zhuǎn)向下一個(gè)結(jié)點(diǎn)
                }
            }
            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
        }
        static void Main()
        {
            var list2 = new LinkedList<int>();//對(duì)泛型實(shí)例化,規(guī)定鏈表只能傳入int
            list2.AddLast(1);//撰寫(xiě)鏈表
            list2.AddLast(3);
            list2.AddLast(5);

            foreach (int i in list2)//遍歷鏈表的值
            {
                WriteLine(i);
            }

            var list3 = new LinkedList<string>();//只能傳入字符串
            list3.AddLast("2");
            list3.AddLast("four");
            list3.AddLast("foo");

            foreach (string s in list3)
            {
                WriteLine(s);
            }
            ReadKey();
        }
    }
}

泛型類的定義與一般類類似循狰,只是要使用泛型聲明窟社。
之后,泛型類型就可以在類中用作一個(gè)字段成員绪钥,或者方法的參數(shù)類型灿里,

        public class LinkedListNode<T>//定義一個(gè)鏈表泛型類
        {
            public T Value;
        }

構(gòu)造函數(shù)也可以變?yōu)榻邮躎類型的對(duì)象,也可以返回和設(shè)置泛型類型程腹。

            public LinkedListNode(T value)//泛型類的構(gòu)造函數(shù)
            {
                Value = value;
            }

泛型類的功能

默認(rèn)值

不能將null賦予泛型類型匣吊,因?yàn)榉盒涂梢詫?shí)例化為值類型,而null只能用于引用類型寸潦。
可以使用 default 關(guān)鍵字將 null在示例化為值類型時(shí)變成0.

        class Test<T>
        {
            public T F()
            {
                T t = null; //有問(wèn)題
                return t;
            }
        }

t在這里無(wú)法編譯色鸳,無(wú)法將null轉(zhuǎn)換為參數(shù)類型T,因?yàn)樗赡苁遣豢梢詾閚ull的值類型见转。
所以需要使用 default

class Test<T>
    {
        public T F()
        {
                return default(T);
        }
    }

default對(duì)應(yīng)各種類型生成默認(rèn)值列表如下

類型 默認(rèn)值
任何引用類型 null
數(shù)值類型 0
bool false
enum 表達(dá)式(E)0生成的值命雀,其中E是枚舉標(biāo)識(shí)符
struct 將所有值類型設(shè)為其默認(rèn)值,將所有引用類型設(shè)為null
可以為null的類型 HasValue屬性為false池户,且Value屬性未定義的實(shí)例

約束

如果泛型類需要調(diào)用泛型類型的方法咏雌,就必須添加約束
泛型接受的約束類型

約束 說(shuō)明
where T : sturct 對(duì)于結(jié)構(gòu)約束,泛型必須是值類型
where T : class 類約束指定類型T必須是引用類型
where T : IFoo 指定類型T必須實(shí)現(xiàn)接口IFoo
where T : Foo 指定類型T必須派生自基類Foo
where T : new() 這個(gè)是一個(gè)構(gòu)造函數(shù)約束校焦,指定類型T必須有一個(gè)默認(rèn)構(gòu)造函數(shù)
where T1: T2 這個(gè)約束也可以指定赊抖,類型T1派生自泛型類型T2

**只能為默認(rèn)構(gòu)造函數(shù)定義構(gòu)造函數(shù)約束,不能為其他構(gòu)造函數(shù)定義構(gòu)造函數(shù)約束寨典。
使用泛型類型還可以合并多個(gè)約束氛雪。

class MyClassy<T1,T2>
where T1: struct
where T2: class耸成,new()
{
      //....
}

指定T1必須是值類型,T2必須是引用類型且必須有一個(gè)默認(rèn)構(gòu)造函數(shù)报亩。

**在C#中,where子句的一個(gè)重要限制是不能定義必須由泛型類型實(shí)現(xiàn)運(yùn)算符井氢,運(yùn)算符不能在接口定義 弦追。在where子句中,只能定義基類花竞,接口和默認(rèn)構(gòu)造函數(shù)劲件,

繼承

泛型類可以實(shí)現(xiàn)泛型接口,也可以派生自一個(gè)類约急,泛型類可以派生自泛型基類零远。

        public class MyClass1<T>
        {
            //.......
        }
        public class MyClass2<T> : MyClass1<T>
        {
            //.......
        }

派生類不必是泛型類

        public class MyClass1<T>
        {
            //.......
        }
        public class MyClass2<T> : MyClass1<string>
        {
            //.......
        }

泛型接口同樣可以被繼承

        interface IMethod<T>
        {
            void f();
        }
        public class MyClass3 : IMethod<int>
        {
            public void f()
            {
                WriteLine(777);
            }
        }

靜態(tài)成員

泛型類的靜態(tài)成員需要特別關(guān)注,泛型類型的靜態(tài)成員只能在類中的一個(gè)實(shí)例中共享厌蔽,

using System;
using static System.Console;

namespace ConsoleApp23
{
    class Program
    {
        public class MyClass<T>
        {
            public static T x;
        }
        static void Main(string[] args)
        {
            MyClass<int>.x = 100;
            MyClass<string>.x = "asdw";
            ReadKey();
        }
    }
}

string牵辣,int是兩個(gè)不同的類型,這樣就出現(xiàn)兩個(gè)不同的靜態(tài)字段x奴饮。

泛型接口

使用泛型可以定義接口纬向,在接口中定義的方法可以帶泛型參數(shù),

泛型接口的協(xié)變和抗變

參數(shù)類型是協(xié)變的戴卜。
泛型參數(shù)定義的類型只能作為方法的返回類型罢猪,不能作為方法的參數(shù)類型,且該類型直接或者間接地繼承自接口方法的返回值類型;可以使用out關(guān)鍵字聲明協(xié)變參數(shù)
如果泛型類型使用 out 關(guān)鍵字做標(biāo)注叉瘩,泛型接口就是協(xié)變的膳帕,這也意味著返回類型只能是T。
如:string->object (子類到父類的轉(zhuǎn)換)

返回的方法是抗變的薇缅。
泛型參數(shù)定義的類型只能作為方法參數(shù)的類型危彩,不能作為返回值類型,且該類型是接口方法的參數(shù)類型的基類型泳桦;可以使用in關(guān)鍵字聲明抗變參數(shù)汤徽。
如果泛型類型使用 in 關(guān)鍵字做標(biāo)注,泛型接口就是抗變的灸撰,這也意味接口只能將類型T用作其方法的輸入谒府。

如:object->string (父類到子類的轉(zhuǎn)換)

泛型結(jié)構(gòu)

與類類似拼坎,結(jié)構(gòu)也可以是泛型的,非常類似于泛型類完疫,但是沒(méi)有繼承泰鸡。

using System;
using static System.Console;

namespace ConsoleApp23
{
    class Program
    {
        public struct MyStruct<T>
        {
            public T A;
            public T B;
        }
        static void Main(string[] args)
        {
            MyStruct<int> s;
            int a = s.A = 100;
            int b = s.B = 777;
            WriteLine(a);
            WriteLine(b);
            ReadKey();
        }
    }
}

泛型方法

在泛型方法中,泛型類型用方法聲明來(lái)定義壳鹤。
泛型方法可以在非泛型類中定義盛龄。

泛型方法示例

using System;
using static System.Console;

namespace ConsoleApp23
{
    class Program
    {
        public class MyClass
        {
            public static void swap<T>(ref T a,ref T b)
            {
                T temp;
                temp = a;
                a = b;
                b = temp;
            }
        }
        static void Main(string[] args)
        {
            int a = 4;
            int b = 10;
            WriteLine("{0}   {1}",a,b);
            MyClass.swap<int>(ref a, ref b);
            WriteLine("{0}   {1}",a,b);
            ReadKey();
        }
    }
}

這里為什么要用ref。ref關(guān)鍵字用于將方法內(nèi)的變量改變后帶出方法外芳誓。

帶約束的泛型方法

泛型類可以用where子句限制余舶,泛型方法也可以用where子句限制,

            public static void swap<T>(ref T a,ref T b) where T: struct
            {
                T temp;
                temp = a;
                a = b;
                b = temp;
            }

帶委托的泛型方法

http://www.reibang.com/p/5a12f3f74c62

泛型方法規(guī)范

泛型方法可以重載锹淌,為特定類型定義規(guī)范匿值,這也適用于帶泛型的方法。

            public  void F<T>(T x)
            {
                WriteLine(x);
            }
            public void F(int x)
            {
                WriteLine(x);
            }
            public void F<T1,T2>( T1 x1,T2 x2)
            {
                WriteLine("{0}  {1}",x1,x2);
            }
            public void F(int x1,int x2)
            {
                WriteLine("{0}  {1}", x1, x2);
            }

上面完成F方法的四次重載赂摆。
在編譯期間千扔,編譯器會(huì)使用最佳匹配。

泛型腦涂概覽

腦圖轉(zhuǎn)載自 牧白 # C#-弄懂泛型和協(xié)變库正、逆變

o_190411-generic-mind.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末曲楚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子褥符,更是在濱河造成了極大的恐慌龙誊,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喷楣,死亡現(xiàn)場(chǎng)離奇詭異趟大,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)铣焊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門逊朽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人曲伊,你說(shuō)我怎么就攤上這事叽讳。” “怎么了坟募?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵岛蚤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我懈糯,道長(zhǎng)涤妒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任赚哗,我火速辦了婚禮她紫,結(jié)果婚禮上硅堆,老公的妹妹穿的比我還像新娘。我一直安慰自己贿讹,他們只是感情好渐逃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著围详,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祖屏。 梳的紋絲不亂的頭發(fā)上助赞,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音袁勺,去河邊找鬼雹食。 笑死,一個(gè)胖子當(dāng)著我的面吹牛期丰,可吹牛的內(nèi)容都是我干的群叶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钝荡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼街立!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起埠通,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赎离,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后端辱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體梁剔,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年舞蔽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荣病。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渗柿,死狀恐怖个盆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情朵栖,我是刑警寧澤砾省,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站混槐,受9級(jí)特大地震影響编兄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜声登,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一狠鸳、第九天 我趴在偏房一處隱蔽的房頂上張望揣苏。 院中可真熱鬧,春花似錦件舵、人聲如沸卸察。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坑质。三九已至,卻和暖如春临梗,著一層夾襖步出監(jiān)牢的瞬間涡扼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工盟庞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吃沪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓什猖,卻偏偏與公主長(zhǎng)得像票彪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子不狮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354