Solidworks二次开发(C++转C#)

目前发现Solidworks二次开发中C#提供的API和环境更为合适,所以将我写的C++插件转换为了C#,由于本人有C++和Java的语法基础,所以本笔记不适用于初学者,学习路线如下:

1.C#学习

学习一门语言,先要学习他的代码规范,这是我让AI给我找的C#的代码规范,后续再补充:

C# 复制代码
- 类名、方法名、属性、接口、命名空间、枚举使用大驼峰(如User)
- 方法名、变量名使用小驼峰(如getName())
- 接口以I开头
- 异步方法以 Async结尾
- 布尔属性用 Is/ Can/ Has开头
- 私有实例字段(_camelCase(下划线 + 小驼峰))
- 私有静态字段(s_camelCase)
- 线程静态字段(t_camelCase)
- 常量(PascalCase),这点和Java还是不一样的

1.1第一个Hello World

其中有两个知识点需要知道:

  • namespace:命名空间是一个声明性区域,用于组织相关类型,并避免名称冲突。简单来说,就是将类、接口、枚举等类型包装在一个作用域中,和C++的定义相似
  • using:允许你使用命名空间中定义的类型,而无需写出其完全限定名。也就是如果你定义了using,就不需要将类型的完整路径写出来了,但是引入的多个命名空间中有同一个类型,使用该类型会编译报错,如程序2所示:
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
            // 这段话的意思是让
            Console.ReadLine();
        }
    }
}

程序2

C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using n1;
using n2;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            A a;
        }
    }
}

namespace n1
{
    class A
    {

    }
}
namespace n2
{
    class A
    {

    }
}

1.2注释

C# 复制代码
// 单行注释

/*
*
*/

/// 三个///快捷注释
/// <summary>
/// 摘要注释
/// </summary>
/// <param name="args">参数注释</param>
static void Main(string[] args)
{
    
}

1.3变量

C# 复制代码
int age = 20;
string name = "Tom";
double salary = 5000;

1.3.1var变量

var是类型推荐的语法糖,变量在编译期就已经确定了类型,之后永远不能改变。var关键字指示编译器根据初始化表达式右侧的结果,推断出变量的类型。

C# 复制代码
var age = 20;

1.4常量

C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            const string PI = "3.1415";
            Console.WriteLine(PI);
            Console.ReadLine();
        }
    }
}

1.4.1const

  • const 是编译期常量
  • const 在编译后被"内联"成值本身
  • const 永远属于类型,不属于对象

1.5数据类型

1.5.1分类

text 复制代码
C# 数据类型
├── 值类型 (Value Types)
│   ├── 简单类型
│   │   ├── 整型(int, long, short, byte...)
│   │   ├── 浮点型(float, double)
│   │   ├── decimal
│   │   ├── bool
│   │   └── char
│   ├── 枚举 enum
│   └── 结构体 struct
│
├── 引用类型 (Reference Types)
│   ├── class
│   ├── interface
│   ├── delegate
│   ├── record
│   ├── string
│   ├── array
│   └── object
│
└── 特殊类型
    └── dynamic

1.5.2值类型

  • 变量直接存储数据本身
  • 存放在栈上(大多数情况)
  • 赋值时会复制整个值
  • 默认按值传递
1.5.2.1整数
类型 大小 范围
sbyte 8 bit -128 ~ 127
byte 8 bit 0 ~ 255
short 16 bit -32768 ~ 32767
ushort 16 bit 0 ~ 65535
int 32 bit ±21亿
uint 32 bit 0 ~ 42亿
long 64 bit ±9×10¹⁸
ulong 64 bit 0 ~ 1.8×10¹⁹
1.5.2.2浮点数
类型 精度 说明
float 7位 单精度
double 15~16位 双精度(默认)
decimal 28~29位 金融/货币计算
1.5.2.3布尔与字符
C# 复制代码
bool isOk = true;
char c = 'A';   // 单引号,16 位 Unicode
1.5.2.4枚举
C# 复制代码
enum Status
{
    Pending,
    Approved,
    Rejected
}
Status s = Status.Approved;
1.5.2.5结构体
C# 复制代码
struct Point
{
    public int X;
    public int Y;
}

1.5.3引用类型

  • 变量存储的是 对象的地址(引用)
  • 对象存放在 堆(Heap)
  • 赋值时只复制引用(两个变量指向同一个对象)
  • 默认按引用传递
1.5.3.1类
C# 复制代码
class Person
{
    public string Name;
    public int Age;
}

Person p1 = new Person();
p1.Name = "Tom";

Person p2 = p1;     // 复制引用
p2.Name = "Jack";

Console.WriteLine(p1.Name); // Jack
1.5.3.2string
C# 复制代码
string s1 = "Hello";
string s2 = s1;
s2 = "World";

Console.WriteLine(s1); // Hello
1.5.3.3数组
C# 复制代码
int[] arr = new int[3];
arr[0] = 10;
1.5.3.4object
C# 复制代码
object o1 = 123;
object o2 = "abc";
1.5.3.4.1装箱和拆箱

我看到的以为一惊,这不是Java中的基本数据类型和包装类的转换吗。但是不对呀,在C#中,没有包装类呀,object不是能包含所有嘛?所以我就迷茫了,然后查了查AI,AI告诉我,在 C# 中,装箱(Boxing)和拆箱(Unboxing) 指的是 值类型(Value Type)与 object(引用类型)之间的转换机制。

  • 装箱:把值类型包装成一个托管堆上的对象
c# 复制代码
int i = 10;
object o = i;   // 装箱
  • 拆箱:把被装箱的对象还原为值类型
c# 复制代码
object o = 10;
int i = (int)o; // 拆箱

1.5.4数据类型转换

1.5.4.1隐式转换

不会丢失数据。

c# 复制代码
int a = 10;

double b = a;
1.5.4.2显式转换
c# 复制代码
double a = 3.14;
// 小数会被截断
int b = (int)a;
1.5.4.3Convert和Parse
c# 复制代码
string age = "18";
int n = Convert.ToInt32(age);
int n = int.Parse("100");
1.5.4.4TryParse
c# 复制代码
bool ok = int.TryParse("100", out int n);

1.6运算符

和Java和C++相似,我就不学了,其中比较生僻的就是??=,特别介绍一下,??=,当变量为 null时,才给它赋值;不为 null就什么都不做。

1.7字符串

C# 里的 string是一个非常"特殊"的类型:语法上像值类型,本质上却是引用类型。

1.7.1三大特性

  • 不可变性:字符串一旦创建,就不能修改(这点和Java相似,Java中字符串也是不可变的,不管是拼接还是substring,本质都是创建一个字符串对象)
  • 字符串驻留:为了节省内存,CLR 会维护一个 字符串常量池(擦,跟Java一摸一样,也是创建维护一个字符串常量池)
  • 重载了==运算符:虽然它是引用类型,但 ==比较的是 内容,不是引用

1.7.2注意点

  • 1.大量拼接使用StringBuilder(和Java一样,也是线程不安全的)

1.7.3常见的方法

C# 复制代码
s.Contains("abc");
s.StartsWith("a");
s.EndsWith("z");
s.IndexOf("a");
s.Substring(0, 5);
s.Split(',');

1.7.4格式化

C# 复制代码
string.Format("Name: {0}, Age: {1}", name, age);
$"Name: {name}, Age: {age}"   // 插值字符串(推荐)

我写的例子如下:

C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Person
    {
        public string name;
        public int age;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person yancey = new Person();
            yancey.age = 26;
            yancey.name = "张三";
            // 格式化
            string s = $"此人的名字是{yancey.name},此人的年纪是{yancey.age}";
            Console.WriteLine(s);
            Console.ReadLine();
        }
    }
}

1.7.5@ 字符串 和 $ 字符串

1.7.5.1@字符串(逐字字符串)

取消字符串中的转义字符处理,让反斜杠 ``被当作普通字符,而不是转义符。并且@字符串可以直接换行

c# 复制代码
string path = @"C:\Users\Admin\Desktop";
1.7.5.2$字符串(插值字符串)

在字符串中直接嵌入表达式(变量、方法调用等),比 string.Format更直观。(string.Format,我靠,真和Java一摸一样),也可以和@字符串组合使用

c# 复制代码
string name = "张三";
int age = 25;
string msg = $"姓名:{name},年龄:{age}";

1.8控制台的输入和输出

C# 复制代码
Console.WriteLine("Hello");
string name = Console.ReadLine();

1.9逻辑控制

1.9.1if-else

c# 复制代码
if(age>18)
{

}
else
{

}

1.9.2三元表达式

c# 复制代码
string result = age > 18 ? "成年" : "未成年";

1.9.3switch

C# 复制代码
// 老版(和java一样,用这个就行)
switch(type)
{
    case 1:
        break;

    case 2:
        break;
}
// 新版
string result = age switch
{
    >18 => "成年",

    _ => "未成年"
};

1.10循环

1.10.1for

c# 复制代码
for(int i=0;i<10;i++)
{

}

1.10.2foreach

c# 复制代码
foreach(var item in list)
{

}

1.10.3while

c# 复制代码
foreach(var item in list)
{

}

1.10.4do while

c# 复制代码
do
{

}while(false);

1.11break continue return

c# 复制代码
- break:退出循环
- continue:跳过本次循环。
- return:结束方法

1.12数组

c# 复制代码
// 一维
int[] nums = {1,2,3};
// 二维
int[,] nums =
{
    {1,2},
    {3,4}
};
// 数组的访问
nums[0];

1.13枚举

c# 复制代码
enum Color
{
    Red,

    Green,

    Blue
}

1.14Nullable

Nullable<T>是一个泛型结构体,用来让"值类型"可以表示 null。常见的写法如下

c# 复制代码
int? age = null;
// 等价于
Nullable<int>

1.15nameof和default

nameof用于在编译期获取变量、类型、成员的名字(字符串),但不会求值。default使用了获取某种类型的默认值。

c# 复制代码
string name = nameof(User.Name);
// 结果是:"Name"
default(int)
// 结果是0

1.16类

我感觉和Java相似,类就是现实世界对象的抽象,一个类通常包括:字段、属性、方法、构造方法、事件

字段、方法、构造方法、this、static、多态都和Java一模一样,但是属性这个东西是Java中没有的,所以我重点记录一下。

1.16.1属性

属性(Property)是 C# 区别于 Java 最关键的语言特性之一,而且它表面上很简单,底下却藏着不少设计哲学。属性是一种用于访问对象状态的成员,它提供灵活的机制来读取、写入或计算私有字段的值。实际我看下来,这玩意就是get方法和set方法的集合,不过还是挺有意思的。这玩意真就是封装的完全体现。

c# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Person
    {
        // 定义两个字段
        private string _name;
        private int _age;

        // 声明属性
        public string Name
        {
            get;set;
        }
        public int Age
        {
            get
            {
                return _age;
            }
            set
            {
                this._age = value;
            }
        }

        // 定义方法
        public string toString()
        {
            return $"我的名字叫做{this._name},我的年龄是{this._age}";
        }
        // 构造方法
        public Person()
        {

        }
        public Person(string name, int age)
        {
            this._age = age;
            this._name = name;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person yancey = new Person("张三", 16);
            Console.WriteLine(yancey.toString());
            Console.ReadLine();
        }
    }
}

1.16.2继承

C#的继承和C++还是比较像的,但是C#中没有继承权限控制。同时和Java也是不一样的,Java调用父类是使用的super关键字,C#使用的是base关键字

c# 复制代码
public class Dog:Animal
{
    public void Test()
    {
        base.Eat();
    }
}

1.16.3virtual、override、abstract

  • virtual:父类说"我可以被重写"
  • override:子类说"我就是要重写它"
  • abstract:父类说"我根本不实现,你们必须实现"
c# 复制代码
using System;

namespace Demo
{
    // 抽象类:动物(不完全的类)
    abstract class Animal
    {
        // abstract:父类不实现,子类必须实现
        public abstract void Speak();

        // virtual:父类有默认实现,子类可选重写
        public virtual void Sleep()
        {
            Console.WriteLine("动物在睡觉");
        }
    }

    // Dog 继承 Animal
    class Dog : Animal
    {
        // override:重写抽象方法(必须)
        public override void Speak()
        {
            Console.WriteLine("狗叫:汪汪");
        }

        // override:重写虚方法(可选)
        public override void Sleep()
        {
            Console.WriteLine("狗趴着睡觉");
        }
    }

    // Husky 继承 Dog
    class Husky : Dog
    {
        // override:继续重写虚方法
        public override void Sleep()
        {
            Console.WriteLine("哈士奇拆家式睡觉");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Animal a1 = new Dog();
            Animal a2 = new Husky();

            a1.Speak();   // 狗叫:汪汪
            a1.Sleep();   // 狗趴着睡觉

            Console.WriteLine("-----");

            a2.Speak();   // 狗叫:汪汪
            a2.Sleep();   // 哈士奇拆家式睡觉
        }
    }
}

1.16.4interface

就是Java中的接口,但是不一样的是Java中类实现接口是通过implement关键字,而C#是通过:,竟然和集成一样,汗颜!

c# 复制代码
public interface IOpenable
{
    void Open();
}
public class Part : IOpenable
{
    public void Open()
    {

    }
}

1.16.4sealed

就是禁止继承,但是可以实现接口

c# 复制代码
public sealed class Logger
{

}

1.16.5readonly

只能构造函数赋值

c# 复制代码
private readonly string _path;

1.16.6partial

把一个类 / 结构体 / 接口 / 方法"拆成多份文件写",编译器在编译时帮你合成一个完整的类型。

编译后等价于

1.16.6record

record就是 "为'存数据'而生的类",默认帮你做好 相等比较、ToString、不可变性,写起来极省代码。本质上就是一个类,但是由record创建的类不能修改,所以我的理解,这玩意就是天生用来创建配置类的(没有自定义方法的)

c# 复制代码
public record Person(string Name, int Age);