C#基礎(chǔ)提升系列——C#委托

C# 委托

委托是類型安全的類捉超,它定義了返回類型和參數(shù)的類型晤愧,委托類可以包含一個(gè)或多個(gè)方法的引用武翎。可以使用lambda表達(dá)式實(shí)現(xiàn)參數(shù)是委托類型的方法榜掌。

委托

當(dāng)需要把一個(gè)方法作為參數(shù)傳遞給另一個(gè)方法時(shí)优妙,就需要使用委托。委托是一種特殊類型的對(duì)象憎账,其特殊之處在于套硼,我們以前定義的所有對(duì)象都包含數(shù)據(jù),而委托包含的只是一個(gè)或多個(gè)方法的地址胞皱。

聲明委托類型

聲明委托類型就是告訴編譯器邪意,這種類型的委托表示的是哪種類型的方法。語(yǔ)法如下:

delegate void delegateTypeName[<T>]([參數(shù)列表]);

聲明委托類型時(shí)指定的參數(shù)反砌,就是該委托類型引用的方法對(duì)應(yīng)的參數(shù)雾鬼。

 //聲明一個(gè)委托類型
 private delegate void IntMethodInvoker(int x);
 //該委托表示的方法有兩個(gè)long型參數(shù),返回類型為double
 protected delegate double TwoLongsOp(double first, double second);
 //方法不帶參數(shù)的委托宴树,返回string
 public delegate string GetString();
 public delegate int Comparison<in T>(T left, T right);

(注:我們把上述定義的Comparison<in T>呆贿、IntMethodInvoker等統(tǒng)稱為委托類型。)

在定義委托類型時(shí)森渐,必須給出它要引用的方法的參數(shù)信息和返回類型等全部細(xì)節(jié)做入。聲明委托類型的語(yǔ)法和聲明方法的語(yǔ)法類似,但沒(méi)有方法體同衣,并且需要指定delegate關(guān)鍵字竟块。

委托實(shí)現(xiàn)為派生自基類System.MulticastDelegate的類,System.MulticastDelegate有派生自基類System.Delegate耐齐。因此定義委托類型基本上是定義一個(gè)新類浪秘,所以可以在定義類的任何相同地方定義委托類型。(可以在類的內(nèi)部定義委托類型埠况,也可以在任何類的外部定義耸携,還可以在命名空間中把委托定義為頂層對(duì)象)。

我們從“delegate”關(guān)鍵字開始辕翰,因?yàn)檫@是你在使用委托時(shí)會(huì)使用的主要方法夺衍。 編譯器在你使用 delegate 關(guān)鍵字時(shí)生成的代碼會(huì)映射到調(diào)用 DelegateMulticastDelegate 類的成員的方法調(diào)用。

可以在類中喜命、直接在命名空間中沟沙、甚至是在全局命名空間中定義委托類型河劝。

建議不要直接在全局命名空間中聲明委托類型(或其他類型)。

使用委托

定義委托類型之后矛紫,可以創(chuàng)建該類型的實(shí)例赎瞎。 為了便于說(shuō)明委托是如何將方法進(jìn)行傳遞的,針對(duì)上述的三個(gè)委托類型颊咬,分別定義三個(gè)方法:

static void ShowInt(int x)
{
    Console.WriteLine("這是一個(gè)數(shù)字:"+x);
}
static double ShowSum(double first,double second)
{
    return first + second;
}
//最后一個(gè)委托务甥,直接可以使用int.ToString()方法,所以此處不再定義

調(diào)用委托有兩種形式喳篇,一種形式是實(shí)例化委托敞临,并在委托的構(gòu)造函數(shù)中傳入要引用的方法名(注意僅僅是方法名,不需要帶參數(shù))杭隙,另一種形式是使用委托推斷,即不需要顯式的實(shí)例化委托因妙,而是直接指向要引用的方法名即可痰憎,編譯器將會(huì)自動(dòng)把委托實(shí)例解析為特定的類型。具體示例如下:

public static void Run()
{
    int a = 10;
    //調(diào)用委托形式一
    IntMethodInvoker showIntMethod = new IntMethodInvoker(ShowInt);
    showIntMethod(a);

    //調(diào)用委托形式二
    TwoLongsOp showSumMethod = ShowSum;
    double sum= showSumMethod.Invoke(1.23, 2.33);
    Console.WriteLine("兩數(shù)之和:"+sum);

    //由于int.Tostring()不是靜態(tài)方法攀涵,所以需要指定實(shí)例a和方法名ToString
    GetString showString = a.ToString;
    string str=showString();
    Console.WriteLine("使用委托調(diào)用a.ToString()方法:"+str);
}

在使用委托調(diào)用引用的方法時(shí)铣耘,委托實(shí)例名稱后面的小括號(hào)需要傳入要調(diào)用的方法的參數(shù)信息。實(shí)際上以故,給委托實(shí)例提供圓括號(hào)的調(diào)用和使用委托類的Invoke()方法完全相同蜗细。委托實(shí)例showSumMethod最終會(huì)被解析為委托類型的一個(gè)變量,所以C#編譯器會(huì)用showSumMethod.Invoke()代替showSumMethod()怒详。

委托實(shí)例可以引用任何類型的任何對(duì)象上的實(shí)例方法或靜態(tài)方法炉媒,只要方法的簽名匹配委托的簽名即可。(所謂簽名昆烁,指的是定義方法或委托時(shí)吊骤,指定的參數(shù)列表和返回類型)

簡(jiǎn)單的委托示例

后面的內(nèi)容將會(huì)基于此示例進(jìn)行擴(kuò)展,首先定義一個(gè)簡(jiǎn)單的數(shù)字操作類MathOperations静尼,代碼如下:

internal class MathOperations
{
    //顯示數(shù)值的2倍結(jié)果
    public static double MultiplyByTwo(double value)
    {
        double result = value * 2;
        Console.WriteLine($"{value}*2={result}");
        return result;
    }
    //顯示數(shù)值的乘方結(jié)果
    public static double Square(double value)
    {
        double result = value * value;
        Console.WriteLine($"{value}*{value}={result}");
        return result;
    }
}

然后定義一個(gè)引用上述方法的委托:

delegate double DoubleOp(double x);

如果要使用該委托的話白粉,對(duì)應(yīng)的代碼為:

DoubleOp op = MathOperations.MultiplyByTwo;
op(double_num);// 假設(shè)double_num為一個(gè)double類型的變量

但是很多時(shí)候,我們并不是直接這樣使用鼠渺,而是將委托實(shí)例作為一個(gè)方法(假設(shè)該方法為A)的參數(shù)進(jìn)行傳入鸭巴,并且將委托實(shí)例引用的方法的參數(shù) 作為另一個(gè)參數(shù)傳遞給該方法A。將上述代碼進(jìn)行封裝轉(zhuǎn)換:

static void ShowDouble(DoubleOp op, double double_num)
{
    double result = op(double_num);
    Console.WriteLine("值為:"+result);
}

調(diào)用該方法:

ShowDouble(MathOperations.MultiplyByTwo, 3);

使用委托一個(gè)好的思路就是拦盹,先定義普通方法鹃祖,然后針對(duì)該方法定義一個(gè)引用該方法的委托,然后寫出對(duì)應(yīng)的委托使用代碼普舆,接著再將使用的代碼用一個(gè)新定義的方法進(jìn)行封裝轉(zhuǎn)換惯豆,在新的方法參數(shù)中池磁,需要指明委托實(shí)例和將要為委托實(shí)例引用的方法傳入的參數(shù)(也就是上述示例中的op和double_num),接著就可以在其他地方調(diào)用該方法了楷兽。

完整的實(shí)例代碼如下:

delegate double DoubleOp(double x);
static void ProcessAndDisplayNumber(DoubleOp action, double value)
{
    double result = action(value);
    Console.WriteLine($"Value is {value },result of operation is {result}");
}
public static void Run()
{
    DoubleOp[] operations = {
        MathOperations.MultiplyByTwo,
        MathOperations.Square
    };
    for (int i = 0; i < operations.Length; i++)
    {
        Console.WriteLine($"Using operations[{i}]:");
        ProcessAndDisplayNumber(operations[i], 2);
        ProcessAndDisplayNumber(operations[i], 3);
        ProcessAndDisplayNumber(operations[i], 4);
    }
}

Action<T>地熄、Func<T>Predicate<T>委托

泛型Action<T>委托表示引用一個(gè)void返回類型的方法芯杀。 該委托類最多可以為將要引用的方法傳遞16種不同的參數(shù)類型端考。

泛型Func<T>委托表示引用一個(gè)帶有返回值類型的方法。該委托類最多可以為將要引用的方法傳遞16中不同的參數(shù)類型揭厚,其中最后一個(gè)參數(shù)代表的是將要引用的方法的返回值類型却特。

泛型Predicate<T> 用于需要確定參數(shù)是否滿足委托條件的情況。 也可將其寫作 Func<T, bool> 筛圆。例如:

Predicate<int> pre = b => b > 5;

此處只對(duì)Action<T>Func<T>做詳細(xì)說(shuō)明裂明。

有了這兩個(gè)委托類,在定義委托時(shí)太援,就可以省略delegate關(guān)鍵字闽晦,采用新的形式聲明委托。

Func<double,double> operations = MathOperations.MultiplyByTwo;
Func<double, double>[] operations2 ={
    MathOperations.MultiplyByTwo,
    MathOperations.Square
};
static void ProcessAndDisplayNumber(Func<double, double> action, double value)
{
    double result = action(value);
    Console.WriteLine($"Value is {value },result of operation is {result}");
}

下面使用一個(gè)示例對(duì)委托的用途進(jìn)行說(shuō)明提岔,首先定義一個(gè)普通的方法仙蛉,該方法是冒泡排序的另一種寫法:

public static void Sort(int[] sortArray)
{
    bool swapped = true;
    do
    {
        swapped = false;
        for (int i = 0; i < sortArray.Length - 1; i++)
        {
            if (sortArray[i] > sortArray[i + 1])
            {
                int temp = sortArray[i];
                sortArray[i] = sortArray[i + 1];
                sortArray[i + 1] = temp;
                swapped = true;
            }
        }
    } while (swapped);
}

上述方法中,接收的參數(shù)局限于數(shù)值碱蒙,為了擴(kuò)展 使其支持對(duì)其他類型的排序荠瘪,并且不僅僅是升序,對(duì)該方法進(jìn)行泛型改寫赛惩,并使用泛型委托哀墓。

internal class BubbleSorter
{
    public static void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison)
    {
        bool swapped = true;
        do
        {
            swapped = false;
            for (int i = 0; i < sortArray.Count - 1; i++)
            {
                if (comparison(sortArray[i + 1], sortArray[i]))
                {
                    T temp = sortArray[i];
                    sortArray[i] = sortArray[i + 1];
                    sortArray[i + 1] = temp;
                    swapped = true;
                }
            }
        } while (swapped);
    }
}

上述方法中的參數(shù)comparison是一個(gè)泛型委托,將要引用的方法帶有兩個(gè)參數(shù)喷兼,類型和T相同麸祷,值可以來(lái)自于sortArray,并返回bool類型值褒搔,因此實(shí)際調(diào)用該委托時(shí)阶牍,不用單獨(dú)的為泛型類型傳入?yún)?shù),直接使用sortArray中的項(xiàng)即可星瘾。

為了更好的調(diào)用該方法走孽,定義如下類:

internal class Employee
{
    public string Name { get; set; }
    public decimal Salary { get; private set; }

    public override string ToString() => $"{Name},{Salary:C}";

    public Employee(string name, decimal salary)
    {
        this.Name = name;
        this.Salary = salary;
    }
    //為了匹配Func<T,T,bool>委托,定義如下方法
    public static bool CompareSalary(Employee e1, Employee e2) => e1.Salary < e2.Salary;
}

使用該類:

Employee[] employees = {
    new Employee("小明",8000),
    new Employee("小芳",9800),
    new Employee("小黑",4000),
    new Employee("小米",13000),
    new Employee("小馬",12000)
};
//調(diào)用排序
BubbleSorter.Sort(employees, Employee.CompareSalary);
ForeachWrite(employees); //輸出結(jié)果琳状,該方法的定義如下:
public static void ForeachWrite<T>(T[] list)
{
    foreach (T item in list)
    {
        Console.WriteLine(item.ToString());
    }
}

多播委托

一個(gè)委托包含多個(gè)方法的調(diào)用磕瓷,這種委托稱為多播委托。多播委托可以識(shí)別運(yùn)算符“+”和“+=“(在委托中添加方法的調(diào)用)以及”-“和”-=“(在委托中刪除方法的調(diào)用)。

多播委托實(shí)際上是一個(gè)派生自 System.MulticastDelegate的類困食,而System.MulticastDelegate又派生自基類System.Delegate边翁。System.MulticastDelegate的其他成員允許把多個(gè)方法調(diào)用鏈接為一個(gè)列表。

internal class MathOperations_V2
{
    public static void MultiplyByTwo(double value)
    {
        double result = value * 2;
        Console.WriteLine($"{value}*2={result}");
    }

    public static void Square(double value)
    {
        double result = value * value;
        Console.WriteLine($"{value}*{value}={result}");
    }
}

針對(duì)上述方法定義一個(gè)帶有泛型委托的方法:

private static void ProcessAndDisplayNumber(Action<double> action, double value)
{
    Console.WriteLine("調(diào)用ProcessAndDisplayNumber方法:value=" + value);
    action(value);
}

使用多播委托的形式進(jìn)行調(diào)用:

Action<double> operations = MathOperations_V2.MultiplyByTwo;
operations += MathOperations_V2.Square;

ProcessAndDisplayNumber(operations, 3);
ProcessAndDisplayNumber(operations, 4);
ProcessAndDisplayNumber(operations, 5);

上述在調(diào)用方法時(shí)硕盹,會(huì)依次執(zhí)行MathOperations_V2.MultiplyByTwoMathOperations_V2.Square符匾。

注意:在使用多播委托時(shí),多播委托包含一個(gè)逐個(gè)調(diào)用的委托集合瘩例,一旦通過(guò)委托調(diào)用的其中一個(gè)方法拋出一個(gè)異常啊胶,整個(gè)迭代就會(huì)停止。

private static void One()
{
    Console.WriteLine("調(diào)用One()方法");
    throw new Exception("Error in one");
}
static void Two()
{
    Console.WriteLine("調(diào)用Two()方法");
}
public static void Run()
{
    Action d1 = One;
    d1 += Two;
    try
    {
        d1();
    }
    catch (Exception)
    {
        Console.WriteLine("調(diào)用d1出錯(cuò)了");
    }
}

上述使用了多播委托垛贤,一旦One出現(xiàn)了異常焰坪,Two并不能夠繼續(xù)執(zhí)行。因?yàn)榈谝粋€(gè)方法拋出了一個(gè)異常聘惦,委托迭代就會(huì)停止某饰,不再調(diào)用Two()方法。為了避免這個(gè)問(wèn)題善绎,應(yīng)自己迭代方法列表黔漂。Delegate類定義GetInvocationList()方法,返回Delegate對(duì)象數(shù)組涂邀,可以迭代這個(gè)數(shù)組進(jìn)行方法的執(zhí)行:

public static void Run2()
{
    Action d1 = One;
    d1 += Two;
    Delegate[] delegates = d1.GetInvocationList();
    foreach (Action d in delegates)
    {
        try
        {
            d();
        }
        catch (Exception)
        {
            Console.WriteLine("調(diào)用出錯(cuò)了N练隆箱锐!");
        }
    }
}

上述迭代比勉,即使第一個(gè)方法出錯(cuò),依然就執(zhí)行第二個(gè)方法驹止。

匿名方法和Lambda表達(dá)式

匿名方法是用作委托的參數(shù)的一段代碼浩聋。

string start = "厲害了,";
Func<string, string> print = delegate (string param)
{
    return start + param;
};
Console.WriteLine(print("我的國(guó)臊恋!"));

在該示例中衣洁,Func<string,string>委托接受一個(gè)字符串參數(shù),返回一個(gè)字符串抖仅。print是這種委托類型的變量坊夫。不要把方法名賦予這個(gè)變量,而是使用一段簡(jiǎn)單的代碼:前面是關(guān)鍵字delegate撤卢,后面是一個(gè)字符串參數(shù)环凿。

匿名方法的優(yōu)點(diǎn)是減少了要編寫的代碼,但代碼的執(zhí)行速度并沒(méi)有加快放吩。

使用匿名方法時(shí)智听,在匿名方法中不能使用跳轉(zhuǎn)語(yǔ)句(breakgotocontinue)調(diào)到該匿名方法的外部,也不能在匿名方法的外部使用跳轉(zhuǎn)語(yǔ)句調(diào)到匿名方法的內(nèi)部到推。并且不能訪問(wèn)在匿名方法外部使用的refout參數(shù)考赛。

實(shí)際使用中,不建議使用上述的方式定義匿名方法莉测,而是使用lambda表達(dá)式颜骤。

只要有委托參數(shù)類型的地方,就可以使用lambda表達(dá)式悔雹,將上述示例改為lambda表達(dá)式复哆,代碼如下:

//使用Lambda表達(dá)式進(jìn)行匿名方法的定義
string start = "厲害了,";
Func<string, string> lambda = param => start + param;
Console.WriteLine(lambda("我的C#!!!"));

使用lambda表達(dá)式規(guī)則:

參數(shù)

只有一個(gè)參數(shù)時(shí)腌零,可以省略小括號(hào)

Func<string, string> oneParam = s => $"將{s}轉(zhuǎn)換為大寫:" + s.ToUpper();
//調(diào)用
Console.WriteLine(oneParam("abc"));

沒(méi)有參數(shù)或者有多個(gè)參數(shù)時(shí)必須使用小括號(hào)

//無(wú)參數(shù)
Action a = () => Console.WriteLine("無(wú)參數(shù)");
a();
//多個(gè)參數(shù)梯找,在小括號(hào)中指定參數(shù)類型
Func<double, double, double> twoParamsWithTypes = (double x, double y) => x + y;
//調(diào)用
Console.WriteLine("2.3+1.3=" + twoParamsWithTypes(2.3, 1.3));

多行代碼

如果lambda表達(dá)式只有一條語(yǔ)句,在方法塊內(nèi)就不需要花括號(hào)({})和return語(yǔ)句益涧,因?yàn)榫幾g器會(huì)添加一條隱式的return語(yǔ)句锈锤。如果lambda表達(dá)式有多條語(yǔ)句,必須顯式的添加花括號(hào)或return語(yǔ)句闲询。例如:

Func<string, string, string> joinString = (str1, str2) =>
  {
      str1 += str2;
      return str1.ToUpper();
  };
Console.WriteLine(joinString("abc", "def"));

閉包

在lambda表達(dá)式的內(nèi)部使用表達(dá)式外部的變量久免,稱為閉包。使用閉包需要注意的一點(diǎn)就是 扭弧,如果在表達(dá)式中修改了閉包的值阎姥,可以在表達(dá)式的外部訪問(wèn)已修改的值 。

委托和 MulticastDelegate 類

System.Delegate 類及其單個(gè)直接子類 System.MulticastDelegate 可提供框架支持鸽捻,以便創(chuàng)建委托呼巴、將方法注冊(cè)為委托目標(biāo)以及調(diào)用注冊(cè)為委托目標(biāo)的所有方法。

有趣的是御蒲,System.DelegateSystem.MulticastDelegate 類本身不是委托類型衣赶。 它們?yōu)樗刑囟ㄎ蓄愋吞峁┗A(chǔ)。 相同的語(yǔ)言設(shè)計(jì)過(guò)程要求不能聲明派生自 DelegateMulticastDelegate 的類厚满。 C# 語(yǔ)言規(guī)則禁止這樣做府瞄。

相反,C# 編譯器會(huì)在你使用 C# 語(yǔ)言關(guān)鍵字聲明委托類型時(shí)碘箍,創(chuàng)建派生自 MulticastDelegate 的類的實(shí)例遵馆。

要記住的首要且最重要的事實(shí)是,使用的每個(gè)委托都派生自 MulticastDelegate丰榴。 多播委托意味著通過(guò)委托進(jìn)行調(diào)用時(shí)货邓,可以調(diào)用多個(gè)方法目標(biāo)。

參考資源

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末多艇,一起剝皮案震驚了整個(gè)濱河市逻恐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖复隆,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拨匆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挽拂,警方通過(guò)查閱死者的電腦和手機(jī)惭每,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)亏栈,“玉大人台腥,你說(shuō)我怎么就攤上這事∪薇保” “怎么了黎侈?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)闷游。 經(jīng)常有香客問(wèn)我峻汉,道長(zhǎng),這世上最難降的妖魔是什么脐往? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任休吠,我火速辦了婚禮,結(jié)果婚禮上业簿,老公的妹妹穿的比我還像新娘瘤礁。我一直安慰自己,他們只是感情好梅尤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布柜思。 她就那樣靜靜地躺著,像睡著了一般克饶。 火紅的嫁衣襯著肌膚如雪酝蜒。 梳的紋絲不亂的頭發(fā)上誊辉,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天矾湃,我揣著相機(jī)與錄音,去河邊找鬼堕澄。 笑死邀跃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛙紫。 我是一名探鬼主播拍屑,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坑傅!你這毒婦竟也來(lái)了僵驰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒜茴,沒(méi)想到半個(gè)月后星爪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粉私,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年顽腾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诺核。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抄肖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窖杀,到底是詐尸還是另有隱情漓摩,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布入客,位于F島的核電站幌甘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痊项。R本人自食惡果不足惜锅风,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞍泉。 院中可真熱鬧皱埠,春花似錦、人聲如沸咖驮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)托修。三九已至忘巧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間睦刃,已是汗流浹背砚嘴。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涩拙,地道東北人际长。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兴泥,于是被迫代替她去往敵國(guó)和親工育。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容