C# 知识点补漏(持续更新)

将以前的一些笔记整理了一下,方便查询知识点

2020-12-23

  • ?用法:

    int ? a=null;表示定义的类型可以为null, 通过a.Value来获取值,它对应的类型是NullAble<T>
    看下面一张图,假如terminalConfiguration为null,它会跳转到if语句中

     

     

     

    Object b = c??d;表示假c==null,返回d,否则返回c,该运算符从右往左运算,即a??b??c为a??(b??c)来计算

  • 字符串拼接
    不推荐使用+,使用string.Format或者$"{param1} {param2} is ..",后两种的底层实现是一样的,效率会更高
    +和string.concat的底层原理是一致的

  • AppDomain

    AppDomain是CLR的运行单元,它可以加载Assembly、创建对象以及执行程序。

    AppDomain是CLR实现代码隔离的基本机制。AppDomain是个静态概念,只是限定了对象的边界

    AppDomain被创建在进程中,一个进程内可以有多个AppDomain。一个AppDomain只能属于一个进程

  • IReadOnlyCollection阻止调用方转换为其他集合类型。 对于这种保护,必须使用类ReadOnlyCollection<T>

  • 一种优雅的转换方式
    string a = "123";
    if(a is object b){
    //then we can use b as objcet
    }
  • 获取变量或者类名推荐使用“nameof()”
    C# 6.0 引入了一个名为“nameof”的新的操作符,它的作用是接收元素而后返回元素名字。这个操作符能将class和class的所用成员,比如方法、变量以及属性作为参数而后返回一个它们的名字。这避免我们在代码中hardcode字符串,也避免使用反射来获得这些名字

  • Marshal.AllocHGlobal 方法 (Int32)
    通过使用指定的字节数,从进程的非托管内存中分配内存

    IntPtr hglobal = Marshal.AllocHGlobal(100); 
    Marshal.FreeHGlobal(hglobal);

     

  • 查看.sln看项目版本
    +---------------------------+---------------+-----------+----------------+
    |       Product name        |   Codename    | Version # | .NET Framework | 
    +---------------------------+---------------+-----------+----------------+
    | Visual Studio 4.0         | N/A           | 4.0.*     | N/A            |
    | Visual Studio 97          | Boston        | 5.0.*     | N/A            |
    | Visual Studio 6.0         | Aspen         | 6.0.*     | N/A            |
    | Visual Studio .NET (2002) | Rainier       | 7.0.*     | 1              |
    | Visual Studio .NET 2003   | Everett       | 7.1.*     | 1.1            |
    | Visual Studio 2005        | Whidbey       | 8.0.*     | 2.0, 3.0       |
    | Visual Studio 2008        | Orcas         | 9.0.*     | 2.0, 3.0, 3.5  |
    | Visual Studio 2010        | Dev10/Rosario | 10.0.*    | 2.04.0      |
    | Visual Studio 2012        | Dev11         | 11.0.*    | 2.04.5.2    |
    | Visual Studio 2013        | Dev12         | 12.0.*    | 2.04.5.2    |
    | Visual Studio 2015        | Dev14         | 14.0.*    | 2.04.6      |
    +---------------------------+---------------+-----------+----------------+ 
    VS 2017 对应 15
    Vs 2019 对应 16

  

  • Resize<T>(ref T[] array, int newSize)
    返回一个新的数组,长度是newSize,并把原数组里面的对应长度的值拷贝到新的数组

  • yield 关键字
    其实是一种语法糖,最终还是通过实现IEnumberable<T>、IEnumberable、IEnumberator<T>和IEnumberator接口实现的迭代功能。
    yield return实现了类似用foreach遍历数组的功能
    yield break是用来终止迭代的
    假如使用yield return 返回的是一个IEnumerable 类型的值

  • 浅拷贝和深拷贝
    浅拷贝的定义 —— 只对值类型(或string)类型分配新的内存地址。

    深拷贝的定义 —— 对值类型分配新的内存地址,引用类型、以及引用类型的内部字段分配的新的地址。

  • winform中的NotifyIcon控件
    NotifyIcon是一个比较特殊的组件,其特殊之处是既可以把它归类到控件中,也可以把它归类到组件中。这是因为将其拖放到设计窗体后,我们并不能马上看到它的界面(像组件),而是在运行时才能看到它(像控件)通知区域中的图标是一些进程的快捷方式,这些进程在计算机后台运行,如防病毒程序或音量控制。这些进程不会具有自己的用户界面。NotifyIcon 类提供了编写此功能的方法。Icon 属性定义显示在通知区域中的图标。图标的弹出菜单由 ContextMenu 属性确定。Text 属性分配工具提示文本。要在通知区域中显示图标,必须将 Visible 属性设置为 true

  • using()方式的使用
    必须确保代码再using的逻辑里面使用,比如memoryStream等流的使用或者数据库,串口的使用,以EFCore为例

     

  • IPropertyChanged事件使用方法

     

     

     

  • IEnumerable, ICollection, ObservableCollection

    IEnumerable只有一个GetEnumerator方法

     

     ICollection继承自IEnumerable,多了增加删除,count等方法

     

     ObservableCollection多了CollectionChanged和PropertyChanged事件,常用于UI

  • 元组的使用方法,当dictionary或者list不够用的时候,推荐使用ValueTuple
    (int intValue, string stringValue, string StringName) name = (intValue: 1, stringValue:"123", StringName: "33");
    var str = name.stringValue;
    var str2 = name.StringName;
    var number = name.intValue;

     

  • Tuple和ValueTuple
    Tuple是引用类型,ValueTuple是值类型,所以推荐用后者

  • 当我们定义接口中的属性时,对于容器一般定义为最顶层的IEnumerable, 那么假如他的实现类的子类需要用到如何办
    public class Test : ITest
    {
        // 公开接口
        public IEnumerable<string> Items => _Items;
        // 私有成员
        private readonly ObservableCollection<string> _Items = new ObservableCollection<string>();
        // 子类操作成员
        protected  ObservableCollection<string> MenuItems => _Items;
    
    }
  • 通常我们定义model都是定义的Immutable,意思是所有成员都是readonly的,只有在构造的时候传入值
    最典型的例子是string,任何操作都会重新创建一个新的string对象
    好处:便于多线程编程,便于作为hashTable的key,便于比较状态
    Immutable离不开2个关键字:const和readOnly
    read only允许在构造的时候改变它的值,但是const不允许,只支持在定义的时候赋值

  • 两种死循环的表达方式 while (true) , for (;;)

  • enum的一些用法

     

  • 获取登录用户名

    string username = System.Environment.UserName;

  • TaskAwaiter的使用
    public class TestTask : IDisposable
    {
        private readonly Command _command;
        private readonly CancellationTokenSource _cancellationTokenSource;
        private readonly Task _executingTask;
    
        public TestTask(Command command)
                {
                    _command = command;
                    _cancellationTokenSource = new CancellationTokenSource();
                    _executingTask = _command.ExecuteAsync(_cancellationTokenSource.Token);
                }
    
        public TaskAwaiter GetAwaiter()
        {
             return _executingTask.GetAwaiter();
        }
        public void Dispose()
        {
               CancelInternal();
               if (_executingTask.Status == TaskStatus.Running)
               {
                        _executingTask.Wait();
               }
    
                _cancellationTokenSource.Dispose();
                _executingTask.Dispose();
         }
    
        private void CancelInternal()
        {
             if (_cancellationTokenSource.IsCancellationRequested)
             {
                   return;
             }
    
              _cancellationTokenSource.Cancel();
         }
    }
    
    class Program
    {
        static void Main(string[] args)
       {
        var task = new TestTask(command);
        await task;
        }
    }

     

  • Expression和Lambda的区别
    看下面的图片,Expression是一个type,把Lambda包装成了一个变量

     

     

  • Lazy<T>的用法
    Lazy表示只有在第一次使用的时候才会去创建对象
    如下图,第一次为false,第二次为true

     

     在unitTest里面使用Substitute

     

     

  • 不要使用magic value

     

     

  • 对IEnumerable<T>的处理方式

     

     

  • 一种设计模式的理解
    IServiceResultFactory<TErrorCode>是总的接口,然后ServiceResultFactory<TErrorCode>是其实现类,CommandCreationResultFactory是ServiceResultFactory的包含特定TErrorCode的子类,那么为什么要多一个ICommandCreationResultFactory来继承自ServiceResultFactory<TErrorCode>.
    很显然,他是CommandCreationResultFactory的接口,它只做一件事,包含特定的TErrorCode,那么外部使用ICommandCreationResultFactory的时候,TErrorCode已经包含,并且因为CommandCreationResultFactory继承自ServiceResultFactory,它包含了所有的IServiceResultFactory<TErrorCode>里面的方法实现。

     

     



  • c#内存
    共有5个内存区域,堆,栈,常量区,静态区,方法区

  • 一个问题

     

     

  • 一个例子
    public class Test {
         public static void main(String[] args) {
             Child demo = new Child();
             demo.function();
             Console.WriteLine("…………………………………………………………………………………………………………………………");
             Child child = new Child();
             child.function();
         }
     }
    
    启动流程:
    
    1、  启动CLR,开始分配内存空间; 
    
    2、  开始加载Test.class文件,加载到方法区中,在加载的过程中静态的内容要进入静态区中;
    
    3、  在开始运行main方法,这时CLR就会把main调用到栈中运行,开始从方法的第一行往下运行;
    
    4、  在main方法中new Child();这时CLR就会在方法区中查找有没有Child文件,如果没有就加载Child.class文件,并且Child继承Parent类,所以也要查找有没有Parent类,如果没有也要加载Parent.class文件。
    
    5、  Child.class和Parent.class中的所有的非静态内容会加载到非静态的区域中,而静态的内容会加载到静态区中。静态内容(静态变量,静态方法)按照书写顺序加载。
    
    说明:类的加载只会执行一次。下次再创建对象时,可以直接在方法区中获取class信息。
    
    6、  开始给静态区中的所有静态的成员变量开始默认初始化。默认初始化完成之后,开始给所有的静态成员变量显示初始化。
    
    7、  所有静态成员变量显示初始化完成之后,开始调用构造函数
    ①有个隐式的super(); 
    
    ②显示初始化(给所有的非静态的成员变量)
    
    ③执行构造代码块
    
    之后才开始执行本类的构造方法中的代码
    
    super()是调用父类的构造函数,此处即为Parent的构造函数,在Parent的构造函数中也有个隐式三步:首先super(),再执行Parent的显示初始化,然后执行Parent的构造函数中的代码。
    
    Parent的执行完之后,回来继续执行Child自己的隐式三步中的第二步:显示初始化,然后执行Child的非静态代码块的,最后执行Child的构造函数中的代码
    
    8、对象创建完成,把内存的地址赋值给demo使用。
    
    9、执行demo.function()方法。
    
    10、由于后面又创建(new)了一个新的Child对象,因此重复一下【7】之后的步骤

     

     

  • 一些概念

    AppDomain: 程序启动得时候会默认创建一个appDomain域

    Application:Encapsulates a Windows Presentation Foundation application. Windows应用程序,WPF和winform都是继承自它

    Window:每一个xaml就是一个window,继承自它。

  • ref和out关键字表示都是传的地址

  • 分割字符串

Regex分割

string[] sArray=Regex.Split(str,"js",RegexOptions.IgnoreCase);

    Split分割

// (以下string words = "1,2.3,,4";):
string[] split = words.Split(new string[] { ",", "." }, 2, StringSplitOptions.RemoveEmptyEntries);//返回:{"1","2.3,,4"} 不保留空元素
string[] split = words.Split(new string[] { ",", "." }, 6, StringSplitOptions.None);//返回:{"1","2","3","","4"} 保留空元素

string[] split = words.Split(new Char[] { ',', '.' }, 2, StringSplitOptions.RemoveEmptyEntries);//返回:{"1","2.3,,4"} 不保留空元素
string[] split = words.Split(new Char[] { ',', '.' }, 6, StringSplitOptions.None);//返回:{"1","2","3","","4"} 保留空元素

 

2021-5-7

Struct 和Class区别

简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上。class是引用类型,创建一个class类型实例被分配在托管堆上。但struct和class的区别远不止这么简单。

概括来讲,struct和class的不同体现在:

● 类是引用类型,struct是值类型
● 在托管堆上创建类的实例,在栈上创建struct实例
● 类实例的赋值,赋的是引用地址,struct实例的赋值,赋的是值
● 类作为参数类型传递,传递的是引用地址,struct作为参数类型传递,传递的是值
● 类没有默认无参构造函数,struct有默认无参构造函数
● 类支持继承,struct不支持继承
● 类偏向于"面向对象",用于复杂、大型数据,struct偏向于"简单值",比如小于16字节,结构简单
● 类的成员很容易赋初值,很难给struct类型成员赋初值
● 类的实例只能通过new SomeClass()来创建,struct类型的实例既可以通过new SomeStruct()来创建,也可以通过SomeStruct myStruct;来创建

 

2021-7-6

使用IDisposable

public class xxx : IDisposable
{
        private bool _disposed;

        /// <summary>
        /// dispose method
        /// </summary>
        /// <param name="disposing">disposing</param>
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;

            if (disposing)
            {
                // dispose your objects
            }

            _disposed = true;
        }

        /// <inheritdoc/>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
}
        

 2021/8/30

通过linq语句判断2个复杂对象是否相同

public static bool AreDataEqual(this PairingEntryDto pairingEntryDto, PairingEntryDto other)
{
            var result = pairingEntryDto.Id == other.Id &&
                         pairingEntryDto.LogTime == other.LogTime &&
                         pairingEntryDto.TerminalSerialNumber == other.TerminalSerialNumber &&
                         pairingEntryDto.ScalePairingHistory.Count == other.ScalePairingHistory.Count;
            if (!result)
                return false;
            return !pairingEntryDto.ScalePairingHistory.Where((t, i) =>
                                                  t.Status != other.ScalePairingHistory[i].Status ||
                                                  t.PairingInformation != other.ScalePairingHistory[i].PairingInformation).Any();
}

2021/9/10

public static Delegate? Combine (params Delegate?[]? delegates);的用法

Delegate.Combine Method (System) | Microsoft Docs

将多个delegate连接,invoke的时候按顺序执行,参数可为null

            Action aa = null;
            Action bb = delegate
            {
                Console.WriteLine("B");
            };
            Action cc = (Action)Delegate.Combine(aa, bb);
            cc();    

上图执行结果为:

 

2021/9/13

函数返回2个结果,设置成元组

public (bool oldState, bool newState) UpdateInitializedState(bool IsInitialized)
{
var oldState = IsInitialized;
var newState = IsInitialized;
return (oldState, newState);
}

 

posted @ 2020-12-23 18:42  小鸡蛋白  阅读(155)  评论(0编辑  收藏  举报