知识提纲
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;
}
}
}
实现很简单,理解起来也不难,但是有个致命的缺点:线程不安全,两个线程可能同事检测到 instance==null成立,因为有可能在一瞬间创建两个。其实在多线程运行时,即使已经在内存中创建了实例,但是内存模型并不能保证新的instance能够看见其它线程所创建的实例。因此这种方法不推荐。下面看看线程安全的方法:
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成员以此来实现锁。这种方法是线程安全的,每个线程要创建实例时,都要先去得锁,然后再判断是否为空,也就是保证多线程运行时,只有一个线程能进行进行实例化,而一旦一个线程实例化后,后面的线程取到锁后,就会发现实例已经创建。但是这个方法也有一个明显的缺点:假设线程足够多,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;
}
}
}
正如你看到的,这个似乎比前面两种实现都要简单,它是如何保证线程安全的呢?对于每个AppDomain,在C#中类的实例被构造或者静态成员被引用时,静态构造函数才会执行,而且只执行一次。由于这个类在一加载就被实例化,因此,效率上要比前面实现高的多。
那为何叫饿汉模式呢?这是因为相对于第2、3的实现方式,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 beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
6. 使用net4之后的Lazy泛型
在.net4之后,可以使用System.Lazy<T>类型实现迟实例化,你唯一需要做的就是传递一个代理便令给单例类的构造函数,可以用lambda表达式轻松实现:
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()
{
}
}
上面的代码会隐式的调用LazyThreadSafetyMode.ExecutionAndPublication以实现lazy<Singleton>线程安全模式.
public override string Tostring
这个是一个很简单的类,他包含两个property name和Age,这里我们就overrid了ToString的函数,你可以使用任何你想要的方式来重写这个函数,只要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);
}
}
调用的代码如下:
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;
}
}
//生成随机数
private static Random random = new Random();
public int RandomNum(int a, int b)
{
return random.Next(a, b);
}
//打印数组的方法
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]);
}
}
}
}
}
调用
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;
//用属性可以简单实现只读属性
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();
//战斗过程
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,触发愤怒被动,攻击力翻倍");
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("女拳第一次死亡,触发复活被动,复活30滴血,继续战斗");
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,触发愤怒被动,攻击力翻倍");
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($"杯子已经空了");
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("水杯初始状态");
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();
}
}
}