C#基础到入门(一篇就够了)(三)

简介: C#基础到入门(一篇就够了)

🍺 字符串


Contains Contains
Remove LastIndexOf
public string Remove(( int startIndex)/ (int startIndex, int count )) public int LastIndexOf( (string/char) value )
CopyTo PadLeft
从 string 对象的指定位置开始复制指定数量的字符到 Unicode 字符数组中的指定位置。 补充左边长度:.PadLeft(2, ‘0’)
Format PadRight
把指定字符串中一个或多个格式项替换为指定对象的字符串表示形式。 补充右边长度:.PadRight(2, ‘0’)
IndexOf Replace
返回指定 Unicode 字符在当前字符串中第一次出现的索引,索引从 0 开始。 替换文字:stringObj.replace(“终古”,“中国”);
Insert Split
返回一个新的字符串,其中,指定的字符串被插入在当前 string 对象的指定索引位置。 返回一个字符串数组,包含当前的 string 对象中的子字符串,子字符串是使用指定的 Unicode 字符数组中的元素进行分隔的。
Join ToLower
连接一个字符串数组中的所有元素,使用指定的分隔符分隔每个元素。 把字符串转换为小写并返回。
Substring ToUpper
string substr = str.Substring(23); 把字符串转换为大写并返回。
Trim
移除当前 String 对象中的所有前导空白字符和后置空白字符。

🍺🍺StringBuilder、重载、递归


⌨⌨StringBuilder


  • 在System.Text命名空间下
  • 所以使用时,需要先引入这个命名空间
usingSystem.Text;
  • 如果不引入,可以直接写:
System.Text.StringBuilderstrB=newSystem.Text.StringBuilder();
  • 使用时,先要new
StringBuilderstringB=newStringBuilder();
  • 追加字符串
//追加字符串stringBuilder.Append("天气好晴朗");
  • 什么时候用StringBuilder而不用string
  • 字符串需要经常修改的时候

⌨⌨⌨方法的重载


  • 同一个类里面,方法名一样,但参数不一样
  • 参数的数据类型不一样
  • 参数的个数不一样
  • 参数的数据类型不一样,个数也不一样
  • 参数个数和类型都一样,但返回值类型不一样,不能算做重载❌
classFuns{
publicstringFun(stringa, stringb)
  {
return"a+b";
  }
publicintFun(inta, intb)
  {
returna+b;
  }
}
Funsfuns=newFuns();
inta=funs.Fun(1, 1);
stringb=funs.Fun("2", "2");
stringc=string.Format("{0},{1}", a, b);
Console.WriteLine(c);
Console.Read();

9.png

image.png

⌨⌨递归


  • 方法自己调用自己
  • 多个方法之间来回调用
  • 使用递归时一定要有出口
  • 使用递归时,一定概要慎重慎重再慎重…

⌨⌨⌨构造函数


执行的时机

new对象()的时候调用

构造函数一般都是public

因为一旦构造函数被设置为了private,那么外界就无法new这个

构造函数没有返回值

也不能写返回值类型

构造函数的名字必须和类名保持完全的一致

构造函数是不能像普通方法一样被直接调用的

关于系统会不会自动创建一个空参空方法体的构造给你

如果一个类没有构造函数

那么系统会自动写一个空参数空方法体的构造函数

如果有构造函数

那么系统就不会帮你自动创建

构造函数可以有参、也可以无参

构造函数是可以重载的

如果想在执行当前构造函数之前,先执行其他的构造函数

当前构造函数(…) : this(传实参)

classPerson{
privateintage;
privatestringname;
publicPerson(intage)
 {
this.age=age;
Console.WriteLine(age);
 }
publicPerson(stringname) : this(18)
 {
this.name=name;
Console.WriteLine(name);
 }
publicPerson(intage, stringname) : this("xian")
 {
Console.WriteLine("我是性别,年龄!");
 }
}
staticvoidMain(string[] args)
{
Personbody=newPerson(128, "alll");
Console.Read();
}

image.png

🍺🍺🍺多态


⌨关于父类空参数构造函数的调用说明


首先,先要明确一点

子类在实例化的时候,必会调用父类的构造函数

子类在声明构造函数的时候,要想办法调用父类的构造

如果父类是空参数的构造函数 : base()

可以不写:base()

系统会默认调用父类的空参数构造

如果父类是有参数的构造函数,那么一定概要通过:base的方式调用,传参

关于VS自动生成类构造函数

右键类名

点击快速修复或重构

点击生成构造

publicclassPerson{
publicstringname;
publicPerson(stringname)
    {
this.name=name;
Console.WriteLine(name);
    }
publicvoidSay()
    {
Console.WriteLine("你在干什么!");
    }
}
publicclassPerson1:Person{
publicPerson1(stringname):base(name)
    {
    }
publicnewvoidSay()
    {
Console.WriteLine("弄啥呢!");
    }
}
publicclassPerson2:Person1{
publicPerson2(stringname) : base(name)
    {
    }
publicnewvoidSay()
    {
Console.WriteLine("搞啥呢!");
    }
}
staticvoidMain(string[] args)
{
Personp=newPerson("1");
p.Say();
Person1p1=newPerson1("2");
p1.Say();
Person2p2=newPerson2("3");
p2.Say();
PersonFun(p2);
Console.ReadLine();
}
publicstaticvoidPersonFun(Personperson)
{
person.Say();
}

image.png

⌨子类方法的覆盖


前提条件:父类中有一个public函数,子类中没有该函数

因为子类中并没有该函数,所以调用必是父类的

前提条件:子类里已经有了该函数,父类里面也有该函数

此时,子类对象调用子类的该函数,父类对象调用父类的该函数

这种子类函数,可以称之为覆盖

子类在书写该函数的时候,规范的写法应该是:

[访问修饰符] new 返回值类型 函数名(参数列表)

覆盖:子类也有该函数了,以后调用的时候就调用子类的该函数

10.png

⌨子类方法的重写【表现出多态】


那么父类的该函数必须是一个虚函数

[访问修饰符] virtual 返回值类型 函数名(参数列表)

子类该怎么重写

[访问修饰符] override 返回值类型 函数名(参数列表)

重写:把子类和父类的该函数都重新写了一遍,有的新的内容

此时,子类的对象,无论是不是转换成了父类的类型,都会执行重写后的该函数

关于VS自动生成类重写函数

右键类名

点击快速修复或重构

点击生成重写

publicclassPerson{
publicstringname;
publicPerson()
   {
   }
publicPerson(stringname)
   {
this.name=name;
   }
publicvirtualvoidSay()
   {
Console.WriteLine("我是父类的方法");
   }
}
publicclassPerson1 : Person{
publicPerson1(stringname)
   {
   }
publicoverridevoidSay()
   {
Console.WriteLine("我是字类的方法");
   }
}
staticvoidMain(string[] args)
{
Person1p1=newPerson1("我是字类");
p1.Say();
Personp=newPerson1("我是父类");
p.Say();
Console.ReadLine();
}

⌨⌨所有类的最终基类:Object


  • 所以,所有类都可以重写Object类中的虚方法
  • Object的虚方法有三个:
  • Equals:描述对象与对象之间是否相等
  • GetHashCode:将一个对象编程一串数字
  • ToString:将一个对象转换为一个字符串

image.png

⌨⌨抽象方法


抽象方法的关键词abstruct

abstruct 返回值类型(参数列表)

抽象方法必须要放在抽象类里面

抽象方法没有方法体: [访问修饰符] abstruct 返回值类型 方法名(形参列表);

抽象方法的访问修饰符不能是private

抽象类即可以放抽象方法,也可以放普通方法

抽象方法必须在子类中全部实现

除非子类也是一个抽象类,那么可以先不实现该抽象方法

抽象方法和虚方法最大的区别

抽象方法必须其派生类中得以实现

而虚方法不是一定要在其派生类去重写

无论是虚方法还是抽象方法,子类进行了重写【实现】

那么子类的子类依旧可以继续重写

抽象类不能用sealed关键词修饰

总结:override可以重写哪些方法呢?

带有virtual、abstruct、override关键词的方法

代码:

//抽象类publicabstractclassPerson{
publicvoidFun(stringname)
    {
Console.WriteLine(name);
    }
publicabstractvoidSay();
}
publicclassPerson1 : Person{
publicoverridevoidSay()
    {
Console.WriteLine("asd");
    }
}
staticvoidMain(string[] args)
{
Person1a=newPerson1();
a.Say();
Console.Read();
}

⌨⌨sealed关键词


sealed关键词修饰的类称之为密封类

语法:sealed class 类名

密封类是不能被别的类继承的

密封方法

sealed关键词修饰的重写的方法,称之为密封方法

语法:sealed override 返回值类型 方法名(参数列表)

密封方法无法再次被其子类重写

代码:

publicclassPerson{
publicvirtualvoidFun()
{
Console.WriteLine(1);
}
}
publicclassPerson1 : Person{
publicsealedoverridevoidFun()
{
Console.WriteLine(2);
}
}
publicclassPerson2 : Person1{
//这里报错 因为续承的Person1是密封函数publicoverridevoidFun()
{
base.Fun();
}
}
staticvoidMain(string[] args)
{
Persona=newPerson1();
a.Fun();
Console.Read();
}

⌨⌨静态类


关键词 static

静态成员

成员:字段、属性、方法

静态:跟对象没有任何关系,只跟类有关系

静态成员在何时开辟的内存

第一次访问这个类的时候【第一次用到这个类的时候】

比如:用这个类名去实例化一个对象

比如:用这个类型去访问一个静态字段

静态成员在何时释放内存

在程序结束的时候才会释放

普通的实例成员,每有一个对象,就有一个该成员

而静态成员,跟对象没有关系,所以无论有多少个对象,静态成员都只有一个

例: 实例成员【name】,每有一个人,就会有对应的一个名字

而静态成员【Population】,跟对象没有关系,无论有多少个实例对象,人口数量只有一个

静态方法中是不可以访问非静态的成员的

不能访问非静态的字段、属性

不能调用非静态的方法

非静态方法中是可以访问静态成员的

能访问静态的字段、属性

能调用静态的方法

静态方法是可以有重载

静态类

静态的成员可以放在静态类中,也可以放在非静态类中

静态类中只能存在静态成员,不能存在非静态的成员

静态类是不能进行实例化的

静态构造函数

只有一种写法

static 类名()

静态构造函数必须无参数

静态构造函数在什么时候才会调用

静态构造函数在程序运行期间只会执行一次

在第一次访问该类的时候调用

用这个类去new一个对象

用这个类去访问某个静态成员

用这个类去调用某个静态方法

如果有继承关系

静态构造函数的执行顺序是:

先执行子类的静态构造,再执行父类的静态构造

先子后父

静态构造有什么作用

一般用于对静态成员进行初始化

代码

classPerson{
publicstaticfloatage=88;
publicstaticvoidFun()
    {
Console.WriteLine("我是父静态类!");
    }
staticPerson()
    {
Console.WriteLine("我是基静态类!");
    }
}
classPer : Person{
staticPer()
    {
Console.WriteLine("我是子静态类!");
    }
}
staticvoidMain(string[] args)
{
Perp=newPer();
Console.WriteLine();
Console.ReadLine();
}

image.png

集合、栈、堆、队列、字典 ✍🔤🔤🔤


1、集合~范型(命名空间using System.Collections.Generic;)


1.1、ArrayList

代码:

//实例化动态数组ArrayListscore=newArrayList();
//向动态数组中添加元素score.Add(90);
score.Add(85.5f);
score.Add("English:100");
int[] array= { 90,80,70 };
//向动态数组中批量添加元素score.AddRange(array);
//向动态数组中插入元素score.Insert(2, "Math:80.5");
//删除动态数组中的元素score.Remove(85.5f);
//删除的是单个约束,如果动态数组中没有该元素,就忽略score.Remove(90);
//根据下标移除动态数组中的元素score.RemoveAt(0);
score.AddRange(newstring[] { "A", "B", "C", "A" });
//批量删除元素score.RemoveRange(2, 3);
//如果数组中没有该下标所对应的元素,则也会出现越界异常Console.WriteLine(score[1]);
//数组元素翻转score.Reverse();    
//一般想要删除某个元素,会先进行判断是否存在boolcontainsA=score.Contains("A");
Console.WriteLine("containsA:"+containsA);
//判断数组中是否包含某个元素if(score.Contains("A"))
{
score.Remove("A");
}
Console.WriteLine("Count:"+score.Count);
//给一个元素的值,查该值在动态数组中的下标Console.WriteLine("IndexOf:"+score.IndexOf(790));
score.Clear();
score.AddRange(newfloat[] { 1.1f,5.7f,4.5f,9.8f,3,2,1});
//从小到大排序score.Sort();
//清空动态数组//score.Clear();Console.WriteLine("-------------");
for (inti=0; i<score.Count; i++)
{
Console.WriteLine(score[i]);
}
Console.WriteLine("-------------");
foreach (variteminscore)
{
Console.WriteLine(item);
}

1.2、List

代码:

//初始化范型集合List<int>list=newList<int>();
//添加元素list.Add(200);
list.Add(250);
list.Add(280);
//批量添加元素list.AddRange(newint[] { 1,3,5,6,7,9 });
//移除某个元素list.Remove(280);
//通过下标移除某个元素list.RemoveAt(0);
list.RemoveAt(0);
//批量删除list.RemoveRange(0, 3);
intindex=list.IndexOf(9);
Console.WriteLine(index);
Console.WriteLine("-----------");
foreach (variteminlist)
{
Console.WriteLine(item);
}

2、栈(Stack )


  • 说明:后进先出

代码:

eg:非范型为例😥

Object<=Stackstack=newStack();
//进栈stack.Push("我是第一个进去的");
stack.Push("我是第二个进去的");
stack.Push("我是第三个进去的");
//出栈Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.Read();
//返回栈顶的元素Peek();

image.png

常用方法

image.png

Stack.TryPeek(T) 方法

返回一个值,该值指示 Stack 的顶部是否有对象;如果有,则将其复制到 result 参数。 不从 Stack 中删除对象。

public bool TryPeek (out T result);

返回

Boolean

如果 Stack 的顶部有对象,则为 true;如果 Stack 为空,则为 false。

Stack.TryPop(T) 方法

public bool TryPop (out T result);

返回一个值,该值指示 Stack 的顶部是否有对象;如果有,则将其复制到 result 参数,并从 Stack 中删除它。

返回

Boolean

如果 Stack 的顶部有对象,则为 true;如果 Stack 为空,则为 false。

3、堆(heaps)


😀😀😀略略略

4、队列(Queue)


说明:先进先出

eg:进列

image.png

eg:出列

image.png

代码:

eg:非范型为例😥

Queuequeue=newQueue();
//进列queue.Enqueue("我是第一个进去的");
queue.Enqueue("我是第二个进去的");
queue.Enqueue("我是第三个进去的");
//出列Console.WriteLine(queue.Dequeue());
Console.WriteLine(queue.Dequeue());
Console.WriteLine(queue.Dequeue());
Console.Read();

image.png

常用方法:

image.png

5、字典(Dictionary)



image.png

代码:

Dictionary<string, int>dis=newDictionary<string, int>();
dis.Add("我是第一个进去的", 1);
dis.Add("我是第二个进去的", 2);
dis.Add("我是第三个进去的", 3);
Console.WriteLine(dis.Values);
Console.WriteLine(dis.ContainsValue(2));
Console.WriteLine(dis.ContainsValue(3));
Console.Read();

6、常见的接口


image.png

🍺🍺🍺🍺单例、接口和范型


1、单例


  • 如果一个对象在声明时直接实例化【new】。
  • 在访问这个类的时候调用
  • 实例化的时间点最早,在静态构造之前就执行了

image.png

2、接口


接口相比类,最大的不同之处在于,只有定义没有实现

接口相当于一堆骨架,实现接口的类,用于填充骨架上的肉

接口不能进行实例化,只能被类或其他接口实现

如即继承类,又实现接口时,类要放在最前面,接口放在后面

eg:

class Person1:Person,jiankou1,jiekou2

11.png

2.1、接口和抽象类的对比

相同点

两者都不能被实例化

两者都包含了由其他类或结构继承或实现的抽象成员不同点

不同点

抽象类当中除了拥有抽象成员外还可以拥有非抽象成员;而接口中所有的所有成员都是抽象的

抽象成员可以使用修饰符修饰,接口当中接口成员访问级别是默认不可修改的,并且默认是public

接口当中不可以包含构造方法,析构方法,静态成员以及常量

C#类只支持单继承,接口支持多支持

3、范型


范型类的构造函数不用写范型类

有些时候重载的方法只有参数类型不同,其他的都一样,这时就可以使用泛型。

泛型:需要用户自己传过来的一个数据类型

平时方法里传递的是参数,是变量,参数传递用的是小括号()。

而泛型传递的是数据类型,泛型传递用的尖括号<>

泛型定义之后,一定要用,不然就没有意义

泛型都在方法的哪里用?

定义参数

在方法体呢使用泛型定义局部变量口

设置返回值类型是一个泛型。给泛型添加约束

给范型舔加约束

方法名(参数列表)where 泛型:约束内容

方法名(参数列表)where 泛型A:约束内容1,约束内容2 where 泛型B:约束内容3

关于泛型方法的重载

如果泛型的个数不同,可以重载

如果泛型的个数相同,但约束不同,不可以重载

关于泛型类和泛型接口

class 类名

类中的字段类型、方法参数、方法返回值,都可以使用类中的泛型

interface 接口名< T >

image.png

代码:

publicclassfanxing{
}
publicstaticvoidFX<T>(Tsex, Tage)
{
Ttemp=sex;
sex=age;
age=temp;
Console.WriteLine(age);
}
publicstaticvoidFX<T>(Tsex, Tage, Ta)
{
Ttemp=sex;
sex=age;
age=temp;
Console.WriteLine(age);
}
staticvoidMain(string[] args)
{
FX<int>(7,8);
FX<float>(7,8);
Console.ReadLine();
}
-范型方法的范型重载eg代码:```代码publicstaticvoidfaning<T>()
{
}
publicstaticvoidfaning<T,F>()
{
}
publicstaticvoidfaning<T,F,U>()
{
}
staticvoidMain(string[] args)
{
faning<>}

12.png

🍺🍺🍺🍺委托与事件


1、委托(delegate)


1.1常见委托类型

  • 什么是委托:相当于中介
  • 委托的别名:代理、句柄
  • 委托是自定义类型
  • 委托是引用类型

代码eg:

eg:非范型为例😥

//定义委托delegatevoidweituo(floatmomey);
classp1{
publicvoidzhao1(floatmomey)
    {
Console.WriteLine("中介一需要:"+momey+"$");
    }
publicvoidzhao2(floatmomey)
    {
Console.WriteLine("中介二需要:"+momey+"$");
    }
publicvoidzhao3(floatmomey)
    {
Console.WriteLine("中介三需要:"+momey+"$");
    }
publicvoidzhao4(floatmomey)
    {
Console.WriteLine("中介四需要:"+momey+"$");
    }
}
internalclassProgram{
staticvoidMain(string[] args)
    {
p1p=newp1();
weituowe;
we=p.zhao1;
we+=p.zhao2;
we+=p.zhao3;
we+=p.zhao4;
we(1232143);
Console.Read();
    }
}

1.2系统委托类型

  1. 无返回值系统委托 Action<>

代码eg:

eg:😥

classp1{
publicvoidwcs()
    {
Console.WriteLine("我是无参数的中介需要:"+"18456456456456"+"$");
    }
publicvoidzhao1(floatmomey)
    {
Console.WriteLine("中介一需要:"+momey+"$");
    }
publicvoidzhao2(floatmomey)
    {
Console.WriteLine("中介二需要:"+momey+"$");
    }
publicvoidzhao3(floatmomey)
    {
Console.WriteLine("中介三需要:"+momey+"$");
    }
publicvoidzhao4(floatmomey)
    {
Console.WriteLine("中介四需要:"+momey+"$");
    }
}
internalclassProgram{
staticvoidMain(string[] args)
    {
p1p=newp1();
//使用系统委托//无参数Actionaction;
action=p.wcs;
action();
//参数Action<float>action1;
action1=p.zhao1;
action1+=p.zhao2;
action1+=p.zhao3;
action1+=p.zhao4;
action1(182);
Console.Read();
    }
}

image.png

2.有返回值系统委托 Func<>

代码eg:

eg:😥

classHout{
}
classp1{
publicstringFunc1()
    {
return"有返回值函数无参数:";
    }
publicHoutFunc2(stringname)
    {
Console.WriteLine("有返回值函数有参数:"+name);
returnnull;
    }
}
internalclassProgram{
staticvoidMain(string[] args)
    {
p1p=newp1();
Func<string>func;
func=p.Func1;
Console.WriteLine(func());
Func<string,Hout>func1;
func1=p.Func2;
Houta=func1("先生");
Console.Read();
    }
}

image.png

1.3委托之匿名函数

代码eg:

eg:😥

classp1{
publicAction<string>action;
publicstringname;
publicintage;
publicp1(stringname, intage)
    {
this.name=name;
this.age=age;
    }
publicvoidisAction(stringage)
    {
Console.WriteLine("我是个中介:"+age);
if (action!=null)
        {
action(age);
Console.WriteLine("我是个中介:"+age);
        }
    }
}
internalclassProgram{
staticvoidMain(string[] args)
    {
p1p=newp1("先生",18);
p.action=delegate (stringa)
        {
Console.WriteLine(a);
Console.WriteLine("我好蒙啊2");
        };
p.action+=read;
p.isAction("我好蒙啊1");
Console.Read();
    }
publicstaticvoidread(stringname)
    {
Console.WriteLine(name);
Console.BackgroundColor=ConsoleColor.Red;
Console.ForegroundColor=ConsoleColor.Black;
    }
}

❌❌❌如何使用VS进行程序调试


程序是从Main函数开始,顺序执行的

调试就是在你觉得可能会发生问题的地方打下断点

什么是断点?

让程序执行到这个地方暂停下来的点

有什么好处,可以一句句或一段段让程序执行

调试步骤

给想要暂停的代码行添加断点

开始调试

通过监视或局部变量窗口,去看此时你想观察的变量的值

如果想看变量or对象的内存地址

找到即时窗口

&变量名

13.png

总结

相关文章
|
7月前
|
存储 编译器 数据处理
C#基础入门之数据类型
C#基础入门之数据类型
|
2月前
|
开发框架 .NET API
RESTful API 设计与实现:C# 开发者的一分钟入门
【10月更文挑战第5天】本文从零开始,介绍了如何使用 C# 和 ASP.NET Core 设计并实现一个简单的 RESTful API。首先解释了 RESTful API 的概念及其核心原则,然后详细说明了设计 RESTful API 的关键步骤,包括资源识别、URI 设计、HTTP 方法选择、状态码使用和错误处理。最后,通过一个用户管理 API 的示例,演示了如何创建项目、定义模型、实现控制器及运行测试,帮助读者掌握 RESTful API 的开发技巧。
82 7
|
2月前
|
C#
C#入门
C#入门
28 0
|
1月前
|
程序员 C# 图形学
全面的C#/.NET自学入门指南
全面的C#/.NET自学入门指南
|
2月前
|
存储 消息中间件 NoSQL
Redis 入门 - C#.NET Core客户端库六种选择
Redis 入门 - C#.NET Core客户端库六种选择
71 8
|
3月前
|
设计模式 C# 开发者
C#设计模式入门实战教程
C#设计模式入门实战教程
|
3月前
|
安全 数据库连接 API
C#一分钟浅谈:多线程编程入门
在现代软件开发中,多线程编程对于提升程序响应性和执行效率至关重要。本文从基础概念入手,详细探讨了C#中的多线程技术,包括线程创建、管理及常见问题的解决策略,如线程安全、死锁和资源泄露等,并通过具体示例帮助读者理解和应用这些技巧,适合初学者快速掌握C#多线程编程。
88 0
|
3月前
|
开发框架 .NET Java
C#/.NET/.NET Core自学入门指南
C#/.NET/.NET Core自学入门指南
|
4月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
110 0
|
4月前
|
开发者 iOS开发 C#
Uno Platform 入门超详细指南:从零开始教你打造兼容 Web、Windows、iOS 和 Android 的跨平台应用,轻松掌握 XAML 与 C# 开发技巧,快速上手示例代码助你迈出第一步
【8月更文挑战第31天】Uno Platform 是一个基于 Microsoft .NET 的开源框架,支持使用 C# 和 XAML 构建跨平台应用,适用于 Web(WebAssembly)、Windows、Linux、macOS、iOS 和 Android。它允许开发者共享几乎全部的业务逻辑和 UI 代码,同时保持原生性能。选择 Uno Platform 可以统一开发体验,减少代码重复,降低开发成本。安装时需先配置好 Visual Studio 或 Visual Studio for Mac,并通过 NuGet 或官网下载工具包。
439 0