前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C# 编程技巧

C# 编程技巧

作者头像
DearXuan
发布2022-01-19 17:58:59
4740
发布2022-01-19 17:58:59
举报

可空类型

概念

在一个类型后面加上问号”?”表示可空类型

例如 int? a 表示a可以是一个数字,也可以是null

转换

对于非空的情况,可以添加显式转换

代码语言:javascript
复制
int? a = 10;
int b = (int)a;
Console.WriteLine(b);

但是当a为null时会报错,因此需要加上if语句

代码语言:javascript
复制
int? a = null;
int b = 
    a == null 
    ? -1 
    : (int)a;
Console.WriteLine(b);
//输出: -1

扩展方法

概念

扩展方法被定义在非泛型静态类中,扩展方法能够为现有的类添加新的方法,而无需定义新的类

示例

幂运算需要用到Math.Pow()函数,通过扩展方法,可以在int类型中添加Pow()方法,更快捷地计算幂

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        int a = 2;
        //计算2的10次方
        Console.WriteLine(a.Pow(10));
        Console.ReadKey();
    }
}
 
public static class Extend
{
    public static int Pow(this int num, int value)
    {
        return (int)Math.Pow(num, value);
    }
}

序列化对象的二进制储存

通过将一个类序列化,可以用二进制的方式在硬盘上保存这个类

代码语言:javascript
复制
[Serializable]
class Struct
{
    public int a = 10;
    public string b = "123";
    public Object c;
}

如果对象中出现对其它对象的引用,那么被引用的对象也会被写入硬盘里,在下次读取时仍然可用

代码语言:javascript
复制
static void Main(string[] args)
{
    Struct s = new Struct()
    {
        a = 99,
        b = "DearXuan",
        c = new Struct()
    };
    //保存
    using(FileStream fileStream1 = new FileStream(@"D:\1.xuan",FileMode.OpenOrCreate))
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        binaryFormatter.Serialize(fileStream1, s);
    }
    //读取
    using (FileStream fileStream = new FileStream(@"D:\1.xuan", FileMode.OpenOrCreate))
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        Struct ss = binaryFormatter.Deserialize(fileStream) as Struct;
        Console.WriteLine(ss.a);
        Console.WriteLine(ss.b);
        Console.WriteLine(((Struct)ss.c).a);
    }
    Console.ReadLine();
}

由于数据是二进制的形式储存,因此文件后缀名可以任意取

UWP的UI线程

UI线程

UI线程维护一个消息队列,所有的UI事件都会被送入消息队列中,在UI线程里执行。如果UI线程中存在耗时操作,就会导致消息得不到及时处理,程序无法响应输入,出现界面卡死

异步任务

使用async修饰方法,使之成为异步任务,用await修饰语句,使之成为等待任务

await修饰的代码将会在子线程中执行,并且不会有返回值

下面的代码生成了一个弹窗,使用await修饰ShowAsync(),使之不会阻塞UI线程

代码语言:javascript
复制
public async static void ShowOKDialog(string title, string content, Action onOkClick, Action onCloseClick)
{
    ContentDialog dialog = new ContentDialog();
    dialog.Title = title;
    dialog.Content = content;
    dialog.PrimaryButtonText = "好的";
    dialog.CloseButtonText = "取消";
    dialog.DefaultButton = ContentDialogButton.Primary;
    if(onOkClick != null)
    {
        dialog.PrimaryButtonClick += (_s, _e) => { onOkClick(); };
    }
    if(onCloseClick != null)
    {
        dialog.CloseButtonClick += (_s, _e) => { onCloseClick(); };
    }
    await dialog.ShowAsync();
}

想要对用户的点击事件做出响应,只需要为“确定”和“取消”按钮添加点击事件即可

跨线程更新UI

使用以下代码将函数放在UI线程执行。如果涉及UI更新的函数在子线程中执行则会报错

代码语言:javascript
复制
public async static void Invoke(Action action, CoreDispatcherPriority Priority = CoreDispatcherPriority.Normal)
{
    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Priority, () => { action(); });
}

默认参数

使用默认参数

直接在方法的参数里为变量赋值,其值会作为默认值传入

代码语言:javascript
复制
public static int add(int a = 5,int b = 10,int c = 15)
{
    return a + b + c;
}

此时调用add(),会返回30

代码语言:javascript
复制
static void Main(string[] args)
{
    Console.Write(add());
    //结果: 30
    Console.ReadLine();
}

覆盖默认参数

按顺序在add()中输入参数,默认参数将会被覆盖

代码语言:javascript
复制
static void Main(string[] args)
{
    Console.Write(add(0,0));
    //结果: 15
    Console.ReadLine();
}
 
public static int add(int a = 5,int b = 10,int c = 15)
{
    return a + b + c;
}

上面的代码在调用add()时输入了两个参数,但是add()有三个参数,因此前两个被覆盖了

如果希望不按顺序,只需要在参数前面加上变量名

代码语言:javascript
复制
static void Main(string[] args)
{
    Console.Write(add(a: 0, c: 0));
    //结果: 10
    Console.ReadLine();
}
 
public static int add(int a = 5,int b = 10,int c = 15)
{
    return a + b + c;
}

上面的代码指定了a和c的变量值为0,而b仍为默认值,因此输出结果10

自动释放资源

IDispose接口

在using语句中定义的对象,将会在脱离using语句后自动释放资源

IDispose接口提供了一种方法来让程序自动释放资源,你需要把释放资源的语句写在Dispose()函数中

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        using(Example example = new Example())
        {
            Console.WriteLine("1");
        }
        // 运行结果:
        // Create
        // 1
        // Dispose
    }
}
 
class Example: IDisposable
{
    public Example()
    {
        Console.WriteLine("Create");
    }
 
    public void Dispose()
    {
        Console.WriteLine("Dispose");
    }
}

在读取文件时,将FileStream定义在using语句中,可以在执行完毕后自动释放,以免长时间占用

代码语言:javascript
复制
using(FileStream fileStream = new FileStream(@"D:\1.xuan",FileMode.OpenOrCreate))
{
    //读取文件
}

析构函数

析构函数与构造函数相反,析构函数在对象被gc释放时调用,因此你无法控制它被调用的具体时间

析构函数中不应该出现任何耗时操作或死循环,否则函数将会被系统强行中断

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        Example example = new Example();
        example = null;
    }
    // 运行结果:
    // Create
    // Dispose
}
 
class Example
{
    public Example()
    {
        Console.WriteLine("Create");
    }
 
    ~Example()
    {
        Console.WriteLine("Dispose");
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021年11月1日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 可空类型
    • 概念
    • 转换
    • 扩展方法
      • 概念
        • 示例
        • 序列化对象的二进制储存
        • UWP的UI线程
          • UI线程
            • 异步任务
            • 跨线程更新UI
            • 默认参数
              • 使用默认参数
                • 覆盖默认参数
                • 自动释放资源
                  • IDispose接口
                    • 析构函数
                    相关产品与服务
                    文件存储
                    文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档