【学习日志】2022.08.26 C#单例模式 Tostring Utils
知識提綱
C#屬性
?
C#單例模式?
0.自用超級簡單式
namespace ConsoleApp2 {//工具類class Utils{private static Utils instance = null;public static Utils Instance{get{if(instance == null){instance = new Utils();}return instance;}}} }?
1.單線程單例模式
public sealed class Singleton{public static Singleton instance = null;private Singleton() { }public static Singleton Instance{get{if (instance == null)instance = new Singleton();return instance;}}}實現(xiàn)很簡單,理解起來也不難,但是有個致命的缺點:線程不安全,兩個線程可能同事檢測到 instance==null成立,因為有可能在一瞬間創(chuàng)建兩個。其實在多線程運行時,即使已經(jīng)在內(nèi)存中創(chuàng)建了實例,但是內(nèi)存模型并不能保證新的instance能夠看見其它線程所創(chuàng)建的實例。因此這種方法不推薦。下面看看線程安全的方法:
2.簡單線程安全
public sealed class Singleton2{private static Singleton2 instance = null;private static readonly object padlock = new object();private Singleton2() { }public static Singleton2 Instance{get{lock(padlock){if (instance == null)instance = new Singleton2();return instance;}}}}
?變化不大,基于前面的分析,這個只是添加了一個object成員以此來實現(xiàn)鎖。這種方法是線程安全的,每個線程要創(chuàng)建實例時,都要先去得鎖,然后再判斷是否為空,也就是保證多線程運行時,只有一個線程能進行進行實例化,而一旦一個線程實例化后,后面的線程取到鎖后,就會發(fā)現(xiàn)實例已經(jīng)創(chuàng)建。但是這個方法也有一個明顯的缺點:假設(shè)線程足夠多,100個吧,每一個線程在進行if(instance==null)判斷時,都到等到某一個線程退出后將鎖獲得。所以會導致性能問題。改進的辦法就是多進行以此判斷,如果instance==null是FALSE,那自然沒必要在等待鎖,再去判斷一次。
3.雙層驗證下的多線程安全
public sealed class Singleton2{private static Singleton2 instance = null;private static readonly object padlock = new object();private Singleton2() { }public static Singleton2 Instance{get{if(null==instance){lock (padlock){if (instance == null)instance = new Singleton2();}}return instance;}}}
4.更高效的單例模式——餓漢模式
public sealed class Singleton3{private static readonly Singleton3 instance = new Singleton3();static Singleton3() { }private Singleton3() { }public static Singleton3 Instance{get{return instance;}}}?正如你看到的,這個似乎比前面兩種實現(xiàn)都要簡單,它是如何保證線程安全的呢?對于每個AppDomain,在C#中類的實例被構(gòu)造或者靜態(tài)成員被引用時,靜態(tài)構(gòu)造函數(shù)才會執(zhí)行,而且只執(zhí)行一次。由于這個類在一加載就被實例化,因此,效率上要比前面實現(xiàn)高的多。
? ? ? ? 那為何叫餓漢模式呢?這是因為相對于第2、3的實現(xiàn)方式,Singleton必選被引用一次后才會將自己實例化,這種成為懶漢式;而當下,無論我們在程序中用不用,編譯器都會實例化一個對象,所以就成為“餓漢模式”
? ? ? ? 那我們看另外一種懶漢模式:
?
5. 懶漢模式——利用嵌套類
public sealed class Singleton {private Singleton(){}public static Singleton Instance { get { return Nested.instance; } }private class Nested{// Explicit static constructor to tell C# compiler// not to mark type as beforefieldinitstatic Nested(){}internal static readonly Singleton instance = new Singleton();} }6. 使用net4之后的Lazy泛型
? ? ? ? 在.net4之后,可以使用System.Lazy<T>類型實現(xiàn)遲實例化,你唯一需要做的就是傳遞一個代理便令給單例類的構(gòu)造函數(shù),可以用lambda表達式輕松實現(xiàn):
public sealed class Singleton {private static readonly Lazy<Singleton> lazy =new Lazy<Singleton>(() => new Singleton());public static Singleton Instance { get { return lazy.Value; } }private Singleton(){} }? 上面的代碼會隱式的調(diào)用LazyThreadSafetyMode.ExecutionAndPublication以實現(xiàn)lazy<Singleton>線程安全模式.
?
public override string Tostring
這個是一個很簡單的類,他包含兩個property name和Age,這里我們就overrid了ToString的函數(shù),你可以使用任何你想要的方式來重寫這個函數(shù),只要return一個string就可以了。
class Person{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return String.Format("Name is {0}, Age is {1}", Name, Age);}}調(diào)用的代碼如下:?
Person person = new Person { Name = "Jason", Age = 20 }; Console.WriteLine(person.ToString());?output:
?
常用工具Utils
using System; using System.Collections.Generic; using System.Text;namespace ConsoleApp2 {//工具類class Utils{private static Utils instance = null;public static Utils Instance{get{if(instance == null){instance = new Utils();}return instance;}}//生成隨機數(shù)private static Random random = new Random();public int RandomNum(int a, int b){return random.Next(a, b);}//打印數(shù)組的方法public static void PrintArray(int[] array){for (int i = 0; i < array.Length; i++){Console.WriteLine(array[i]);}}public static void PrintArray(int[,] array){for (int i = 0; i < array.GetLength(0); i++){for (int j = 0; j < array.GetLength(1); j++){Console.WriteLine(array[i, j]);}}}} }調(diào)用
Utils.Instance.RandomNum(1,100);范例
題目
我的解答
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;namespace mhls {class CharacterManager{private static CharacterManager instance = null;public static CharacterManager Instance{get{if (instance == null){instance = new CharacterManager();}return instance;}}Character[] all = new Character[100];int index = 0;public Character CreateCharacter(string name, int hp, int attack, int def){Character c = new Character(name, hp, attack, def);all[index] = c;index++;return c;}public void PrintAll(){for (int i = 0; i < index; i++){Character c = all[i];Console.WriteLine(all[i]);}}}class Character{public string name;//用屬性可以簡單實現(xiàn)只讀屬性public int attack { get; set; }public int def;public int hp;public Character(){name = "未知";}public Character(string name, int hp, int attack, int def){this.name = name;this.hp = hp;this.attack = attack;this.def = def;}public void CostHp(int cost){this.hp -= cost;if (this.hp <= 0){this.hp = 0;}}public bool IsDead(){return hp <= 0;}public override string ToString(){return $"角色:{name} HP:{hp} 攻擊力:{attack} 防御力:{def}";}}class Program{static void Main(string[] args){Character c1 = CharacterManager.Instance.CreateCharacter("男拳", 100, 15, 1);Character c2 = CharacterManager.Instance.CreateCharacter("女拳", 70, 10, 10);CharacterManager.Instance.PrintAll();Console.WriteLine();//戰(zhàn)斗過程while (!c1.IsDead() && !c2.IsDead()){if (c1.hp > 20){int cost1 = c1.attack - c2.def;c2.CostHp(cost1);Console.WriteLine($"{c1.name}攻擊了{c2.name},{c2.name}損失了{cost1}血量");Console.WriteLine(c1);Console.WriteLine(c2);Console.WriteLine();}else{Console.WriteLine("男拳血量少于20,觸發(fā)憤怒被動,攻擊力翻倍");int cost2 = 2 * c1.attack - c2.def;c2.CostHp(cost2);Console.WriteLine($"{c1.name}攻擊了{c2.name},{c2.name}損失了{cost2}血量");Console.WriteLine(c1);Console.WriteLine(c2);Console.WriteLine();}if (c2.IsDead()){break;}int cost = c2.attack - c1.def;c1.CostHp(cost);Console.WriteLine($"{c2.name}攻擊了{c1.name},{c1.name}損失了{cost}血量");Console.WriteLine(c1);Console.WriteLine(c2);Console.WriteLine();}//判斷勝負if (c1.IsDead()){Console.WriteLine($"------{c2.name}勝利!------");Console.WriteLine();}else{Console.WriteLine("女拳第一次死亡,觸發(fā)復活被動,復活30滴血,繼續(xù)戰(zhàn)斗");Character c3 = CharacterManager.Instance.CreateCharacter("女拳", 30, 10, 10);Console.WriteLine(c1);Console.WriteLine(c3);Console.WriteLine();while (!c1.IsDead() && !c3.IsDead()){if (c1.hp > 20){int cost3 = c1.attack - c3.def;c3.CostHp(cost3);Console.WriteLine($"{c1.name}攻擊了{c3.name},{c3.name}損失了{cost3}血量");Console.WriteLine(c1);Console.WriteLine(c3);Console.WriteLine();}else{Console.WriteLine("男拳血量少于20,觸發(fā)憤怒被動,攻擊力翻倍");int cost4 = 2 * c1.attack - c3.def;c3.CostHp(cost4);Console.WriteLine($"{c1.name}攻擊了{c3.name},{c3.name}損失了{cost4}血量");Console.WriteLine(c1);Console.WriteLine(c3);Console.WriteLine();}if (c3.IsDead()){break;}int cost5 = c3.attack - c1.def;c1.CostHp(cost5);Console.WriteLine($"{c3.name}攻擊了{c1.name},{c1.name}損失了{cost5}血量");Console.WriteLine(c1);Console.WriteLine(c3);Console.WriteLine();}if (c1.IsDead()){Console.WriteLine($"------{c3.name}勝利!------");Console.WriteLine();}else{Console.WriteLine($"------{c1.name}勝利!------");}Console.ReadKey();}}} }題目
?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;namespace shuihu {class Shuihu{public string name;public int capacity;public int water { get; set; }public int temperature;public Shuihu(string name,int capacity,int water,int temperature){this.name = name;this.capacity = capacity;this.water = water;this.temperature = temperature;}public void addwater(int a){if(a<(this.capacity- this.water)){this.water += a;Console.WriteLine($"添加{a}毫升的水");Console.WriteLine();}else{int y = (this.water + a - this.capacity);this.water = this.capacity; Console.WriteLine($"添加{a}毫升的水");Console.WriteLine("水已注滿,溢出" + y + "毫升");Console.WriteLine();}}public void pumpwater(int a){if (a < this.water){this.water -= a;Console.WriteLine($"抽出{a}毫升的水");Console.WriteLine();}else{this.water = 0;Console.WriteLine($"杯子已經(jīng)空了");Console.WriteLine();}}public void heatwater(int a){if(this.water != 0){if (a > this.temperature && a < 100){this.temperature = a;Console.WriteLine($"水溫已加熱至{a}攝氏度");Console.WriteLine();}else if (a < this.temperature){Console.WriteLine($"當前水溫為{this.temperature}攝氏度,無法降溫");Console.WriteLine();}else{Console.WriteLine($"水溫最多加至100攝氏度,當前水溫為{this.temperature}攝氏度");Console.WriteLine();}}else{Console.WriteLine("被子里面沒有水,無法加熱");}}public override string ToString(){return $"{name} 容量{capacity} 水量{water} 溫度{temperature}";}}class Program{static void Main(string[] args){Shuihu H1 = new Shuihu("小茶杯",100,0,30);Console.WriteLine("水杯初始狀態(tài)");Console.WriteLine(H1.ToString());Console.WriteLine();Console.WriteLine($"請輸入加水量____毫升");int add = int.Parse(Console.ReadLine());H1.addwater(add);Console.WriteLine(H1.ToString());Console.WriteLine();Console.WriteLine($"請輸入抽水量____毫升");int sub = int.Parse(Console.ReadLine());H1.pumpwater(sub);Console.WriteLine(H1.ToString());Console.WriteLine();Console.WriteLine($"請輸入目標溫度____");int tem = int.Parse(Console.ReadLine());H1.heatwater(tem);Console.WriteLine(H1.ToString());Console.WriteLine();}} }?
?
總結(jié)
以上是生活随笔為你收集整理的【学习日志】2022.08.26 C#单例模式 Tostring Utils的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大O表示法(复杂度分析)
- 下一篇: ValueError: With n_s