当一个类设计好后.它的属性.字段,方法等都会固定下来.如果要在后期添加新功能.有多种办法
1,直接修改. 用于类比较小,修改的地方也少.就这样直接修改
2,继承一个接口,然后实现接口. 这是常用的.体现了继承的优点. 也有缺点.当类比较多时候.要全部都修改.
3,适配器模式.新建一个类,传入原对象.并继承接口.体现了低耦合,高内聚.如:
internal interface I新功能
{
void 飞();
}
internal class 新对象 : I新功能
{
private 对象 _对象;
public 新对象(对象 对象1)
{
_对象 = 对象1;
}
#region I新功能 Members
public void 飞()
{
}
#endregion
}
下面要介绍的是让类拥有学习功能.在后期如果再要添加功能就可以学习后再使用.
先让类继承于 智能化接口. 再建立针对于这个类的学校. 当对象需要新功能的时候.就让对象去学校学习.
然后就可以调用对象的新功能了.
internal interface I智能化
{
/// <summary>
/// int 为技能的哈希码. obj为技能.
/// </summary>
/// <value>The 技能.</value>
Dictionary<int, object> 技能 { get; set; }
/// <summary>
/// T 为学会的技能
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T 使用<T>();
}
internal interface I学校
{
/// <summary>
/// T 为要学习的技能
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="智能对象">The 智能对象.</param>
void 教学<T>(I智能化 智能对象);
}
internal class 学校 : I学校
{
#region I学校 Members
public void 教学<T>(I智能化 智能对象) //可以有限制,或者其他限制
{
var h = typeof (T).GetHashCode();
if (智能对象.技能.ContainsKey(h))
{
return; //存在技能就返回.
}
T 新技能 = default (T); //此处可以对技能做更多操作初始化.
智能对象.技能.Add(h, 新技能);
}
#endregion
}
internal class 飞
{
public void 飞翔()
{
//...
}
public void 降落()
{
}
}
上面建立了通用的智能化接口. 学校接口.和一个新技能飞翔.
下面是对象的建立.
internal class 对象 : I智能化
{
public 对象()
{
技能 = new Dictionary<int, object>();
}
#region I智能化 Members
public T 使用<T>()
{
int h = typeof (T).GetHashCode();
if (技能.ContainsKey(h))
{
return (T) 技能[h];
}
return default(T);
}
public Dictionary<int, object> 技能 { get; set; }
#endregion
}
对象拥有技能列表.我还没找到怎么用泛型代替.先用万能对象.
客户端调用如下:
internal class 客户
{
private 对象 对象1;
public 客户()
{
对象1 = new 对象();
演示();
}
private void 演示()
{
I学校 学校1 = new 学校();
学校1.教学<飞>(对象1);
对象1.使用<飞>().飞翔();
}
}
学校可以对不同的类教学不同的技能, 可以泛型化.
具体表现有更多可以优化的地方.先记录下来,抛砖引玉.
使用了事件返回 音频长度.
大部分用的是中文名称.注释就不写了.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Threading;
namespace 编程帮助
{
public interface II媒体长度
{
void 歌曲长度(string filename);
TimeSpan 检测超时时间 { get; set; }
event EventHandler<E媒体长度> 长度报告;
}
public class E媒体长度 : EventArgs
{
public E媒体长度(string 文件, TimeSpan 长度)
{
this.文件 = 文件;
this.长度 = 长度;
}
public string 文件 { get; set; }
public TimeSpan 长度 { get; set; }
}
public class CC媒体长度 : II媒体长度
{
System.Windows.Media.MediaPlayer p;
private string 歌曲;
public event EventHandler<E媒体长度> 长度报告 = delegate { };
private TimeSpan 长度;
private DispatcherTimer 时间线;
public CC媒体长度()
{
歌曲 = string.Empty;
长度 = TimeSpan.Zero;
p = new System.Windows.Media.MediaPlayer();
p.IsMuted = true;
p.MediaFailed += new EventHandler<System.Windows.Media.ExceptionEventArgs>(p_MediaFailed);
p.MediaOpened += new EventHandler(p_MediaOpened);
时间线 = new DispatcherTimer();
时间线.Interval = TimeSpan.FromSeconds(5); //超时时间
时间线.Tick += new EventHandler(时间线_Tick);
}
void 时间线_Tick(object sender, EventArgs e)
{
零长度报告();
}
void p_MediaOpened(object sender, EventArgs e)
{
长度 = (p.NaturalDuration.HasTimeSpan) ? p.NaturalDuration.TimeSpan : TimeSpan.Zero;
标准长度报告();
}
void p_MediaFailed(object sender, System.Windows.Media.ExceptionEventArgs e)
{
零长度报告();
}
private void 零长度报告()
{
长度 = TimeSpan.Zero;
标准长度报告();
}
private void 标准长度报告()
{
时间线.Stop();
p.Stop();
长度报告(this, new E媒体长度(歌曲, 长度));
}
public void 歌曲长度(string filename)
{
try
{
p.Close();
歌曲 = filename;
时间线.Start();
p.Open(new Uri(filename));
}
catch (Exception)
{
零长度报告();
}
}
public TimeSpan 检测超时时间
{
get { return 时间线.Interval; }
set { 时间线.Interval = value; }
}
}
}
第1种用 Task类. 推荐用这个办法
public void 工作_Task()
{
Dispatcher x = Dispatcher.CurrentDispatcher;//取得当前工作线程
//另开线程工作
Task<int> 计数 = new Task<int>(() => { return 计数方法(); });
计数.ContinueWith(工作完毕后方法);//工作完毕后执行的方法
计数.Start();//开始工作
}
public void 工作完毕后方法(Task<int> 参数)
{
if (参数.IsCompleted) //正常工作完毕
{
var 结果 = 参数.Result; //取得结果
//处理结果.
//本方法非界面线程.如果需要在界面线程操作,需要转移到界面线程
}
}
int c;
public int 计数方法()
{
return c++;
}
第2种方法用线程.
public void 工作_Thread()
{
Dispatcher x = Dispatcher.CurrentDispatcher;//取得当前工作线程
//另开线程工作
System.Threading.ThreadStart start = delegate()
{
//工作函数
Func<string> fu = new Func<string>(() => { return ""; });//工作函数
var 工作结果 = fu();//开始工作
//异步更新界面
x.BeginInvoke(new Action(() =>
{
//在界面线程操作 可以使用 工作结果
}), DispatcherPriority.Normal);
};
new System.Threading.Thread(start).Start(); //启动线程
}
第3种方法用 BackgroundWorker.
这种方法介绍的比较多了.就不说了.
BackgroundWorker 后台线程;
public void 线程初始化()
{
后台线程 = new BackgroundWorker();
后台线程.WorkerSupportsCancellation = true; //可以取消
后台线程.DoWork += new DoWorkEventHandler(后台线程_DoWork);
后台线程.RunWorkerCompleted += new RunWorkerCompletedEventHandler(后台线程_RunWorkerCompleted);
}
public void 启动后台线程()
{
后台线程.RunWorkerAsync();
}
void 后台线程_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//工作完毕的方法
}
void 后台线程_DoWork(object sender, DoWorkEventArgs e)
{
//工作方法
}
针对WPF 的依赖属性.可以监听后,添加自己的事件处理程序;
属性名称 需要是依赖属性名,
控件可以是监听的类型.
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(属性名称, typeof(控件名称));
if (dpd != null)
{
dpd.AddValueChanged(控件实例, delegate
{
//处理程序
});
}
示例:

View Code
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(UC登录.登录成功Property, typeof(UC登录));
if (dpd != null)
{
dpd.AddValueChanged(uC登录1, delegate
{
if (uC登录1.登录成功 )
{
this.Close();
}
});
}
WPF 专用属性,可以实现界面自动更新.
类需要继承自 DependencyObject
需要引用: using System.Windows;
属性声明如下. 用代码片段 输入比较快. 按dp +tab+tab + 0 完成.
代码片段下载:http://drwpf.com/blog/2010/04/30/updated-code-snippets/
#region IsSwanky
/// <summary>
/// IsSwanky Dependency Property
/// </summary>
public static readonly DependencyProperty IsSwankyProperty =
DependencyProperty.Register("IsSwanky", typeof(bool), typeof(类名),
new FrameworkPropertyMetadata((bool)false));
/// <summary>
/// Gets or sets the IsSwanky property. This dependency property
/// indicates ....
/// </summary>
public bool IsSwanky
{
get { return (bool)GetValue(IsSwankyProperty); }
set { SetValue(IsSwankyProperty, value); }
}
#endregion
WPF 绑定数据专用列表:
ObservableCollection<T>
可以实现界面自动更新.需要引用 :
using System.Collections.ObjectModel;
如果需要在界面上显示的基本上就用这个列表了.可以替代 List<T>, 不知道能不能传入到后台线程处理数据.
用的DependencyProperty 属性就不能传入后台处理.还要写个CLR类传到后台处理. 还在找其他的办法.
用程序自动关机.
下面是关机方法,调用了系统自带的关机命令. 如果需要定时关机.只需要用定时器.到时间调用此命令即可.

View Code
public static void 关机(string 运行命令 ="shutdown -s -t 30")
{
var s = 运行命令;
if (string.IsNullOrEmpty(s)) { return; }
string 程序 = string.Empty;
string 参数 = string.Empty;
int a = s.IndexOf(" ");
if (a < 0)
{
程序 = s;
}
else
{
程序 = s.Substring(0, a);
参数 = s.Remove(0, a);
}
System.Diagnostics.Process 进程 = new System.Diagnostics.Process();
进程.StartInfo.FileName = 程序;
进程.StartInfo.Arguments = 参数;
进程.Start();
}
有时候需要调整系统时间来测试程序.
用DOS命名可以做到.此方法也可以运行其他DOS 命令.或者其他程序.
方法如下:
public void cmd()
{
var process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
//在需要的地方写入命令
process.StandardInput.WriteLine("time 0" );
}
有时候用到要把字符串的列表 合并.以前是自己写个方法.
现在.NET 4有自己的方法了.
public void 合并字符串()
{
var stringlist = new List<string>() { "你", "我", "他" };
var 连接整个字符 = string.Concat(stringlist);
var 连接字符并换行 = string.Join("\r\n", stringlist);
}
还有一个新类型比较好用: 元组.
当一个方法需要返回多个数据的时候.用用.或者要临时传递多参数时.
public 元组()
{
//可以声明1到8个或更多.
//用途:
//可以传递多个参数,返回多个参数.
Tuple<string, string, int> 临时组合类 =
new Tuple<string, string, int>("姓名","年龄",18);
//也可以声明匿名类.
var 新类 = new { 姓名 = "", 性别 = "" };
}
需要引用 微软的 一个拼音控件.
using Microsoft.International.Converters.PinYinConverter;
可以在微软官方下载 CHSPinYinConv.msi.安装即可引用
缺点:无法识别重音字.
已经声明为扩展方法.任何汉字字符串都可以调用了.
方法名有kk是为了在引用的时候输入更快定位到扩展方法.
public static partial class KK扩展方法
{
public static string kk拼音首字母(this string 汉字)
{
StringBuilder r = new StringBuilder();
foreach (var item in 汉字)
{
if (ChineseChar.IsValidChar(item)) //是汉字 返回首字母
{
r.Append(new ChineseChar(item).Pinyins[0][0]);
}
else if (char.IsNumber(item)) //是数字 返回本身
{
r.Append(item);
}
else if (char.IsLetter(item)) //是字母 转大写
{
r.Append(char.ToUpper(item));
}
}
return r.ToString();
}
}
查找速度比较快的是查找表
字母表上传不上,可以网上搜索出来. 基本是1毫秒查找1万字.
方法如下:

View Code
public static string Get汉字首字母(string 字符串)
{
if (string.IsNullOrEmpty(字符串)) return string.Empty;
var 结果 = new StringBuilder();
foreach (char vChar in 字符串)
{
int c = (int)vChar - 19968;
if ((vChar >= '0' && vChar <= '9') || (vChar >= 'a' && vChar <= 'z') || (vChar >= 'A' && vChar <= 'Z')) // 若是字母和数字则直接输出
结果.Append(char.ToUpper(vChar));
else if (c >= 0 && c < 20902) // 对可以查找的汉字计算它的首拼音字母的位置,然后输出
{
结果.Append(首字母表[c]);
}
}
return 结果.ToString();
}
本想自己生成字母表的.结果是不能用.方法如下:

View Code
public string 字母表(int 开始 = 19968, int 结束 = 40870)
{
StringBuilder r = new StringBuilder();
string cr;
for (int i = 开始; i < 结束; i++)
{
cr = char.ConvertFromUtf32(i);
if (ChineseChar.IsValidChar(cr[0]))
{ //好像不全.只能输出20538个字母
r.AppendLine(string.Format("{0} {1} {2} ", i.ToString(), cr, new ChineseChar(cr[0]).Pinyins[0][0]));
//r.Append(string.Format("{0}", new ChineseChar(cr[0]).Pinyins[0][0]));
}
}
return r.ToString();
}