it编程 > 编程语言 > Java

Java快速转C#的简明教程

4人参与 2025-07-26 Java

以下是一个针对 java 开发者快速转向 c# 的简明教程,重点对比 java 与 c# 的异同,帮助你快速上手。

项目结构:

一、基础语法对比

1.变量与数据类型

javac#
int a = 10;int a = 10;
string name = "hello";string name = "hello";
final int max = 100;const int max = 100;
var list = new arraylist<>(); (java 10+)var list = new list<string>();

c# 特色:

2.拓展方法

c# 的扩展方法允许你为现有类型 (包括密封类、接口、甚至第三方库的类型)“添加”方法,而无需修改其源代码或继承。这是 c# 特有的语法特性,java 中无直接等价物(需通过工具类或继承实现)。

定义扩展方法

// 静态类:扩展方法容器
public static class stringextensions {
    // 扩展 string 类型的方法
    public static bool isnullorempty(this string str) {
        return string.isnullorempty(str);
    }
}

使用拓展方法

string name = null;

// 调用扩展方法(如同实例方法)
if (name.isnullorempty()) {
    console.writeline("name is null or empty");
}

值得注意的是,拓展方法作为一个语法糖对应的可以解决在java中 xxutils 的工具类。同时具有以下注意:

3.空运算符(null handling operators)

c# 提供了强大的空值处理运算符,简化空值检查逻辑,避免 nullreferenceexception

1. 空条件运算符(?.)

用于安全访问对象的成员,若对象为 null 则返回 null 而非抛出异常。

person person = getperson(); // 可能为 null

// 安全访问属性和方法
int length = person?.name?.length ?? 0;
person?.sayhello();

对比 java

2. 空合并运算符(??)

提供默认值,当左侧表达式为 null 时返回右侧值。

string name = null;
string displayname = name ?? "guest"; // 如果 name 为 null,则使用 "guest"

对比 java

3. 空合并赋值运算符(??=)

仅当变量为 null 时才赋值(c# 8.0+)。

string message = getmessage();
message ??= "default message"; // 如果 getmessage() 返回 null,则赋值为默认值

对比 java

4. 非空断言运算符(!)

告知编译器某个表达式不为 null(c# 8.0+,用于可空引用类型上下文)。

string name = getname()!; // 告诉编译器 getname() 返回值不为 null

注意事项

二、面向对象编程

1.类与对象

public class person {
    // 字段
    private string name;

    // 属性(推荐封装字段)
    public string name {
        get { return name; }
        set { name = value; }
    }

    // 构造函数
    public person(string name) {
        this.name = name;
    }

    // 方法
    public void sayhello() {
        console.writeline($"hello, {name}");
    }
}

对比 java:

2.继承与接口

// 继承
public class student : person {
    public student(string name) : base(name) {}
}

// 接口
public interface irunnable {
    void run();
}

public class car : irunnable {
    public void run() {
        console.writeline("car is running");
    }
}

对比 java:

三、c# 特有特性

1.委托与事件(delegates & events)

// 委托(类似 java 的函数式接口)
// 定义一个名为 notify 的委托类型,它表示一种方法模板,要求方法返回 void 并接受一个 string 参数
// 类比 java :类似 java 中的函数式接口(如 consumer<string>),但 c# 的委托更直接,可以直接绑定方法。
public delegate void notify(string message);

// 事件
public class eventpublisher {
	// 声明一个事件 onnotify,其类型是 notify 委托。事件本质上是委托的安全封装,外部只能通过 +=/-= 订阅/取消订阅,不能直接调用(如 onnotify.invoke() 会报错)。
    public event notify onnotify;

	// 调用 onnotify?.invoke(...) 触发事件,?. 是空值保护操作符(避免空引用异常)。只有当至少有一个订阅者时,才会执行。
    public void triggerevent() {
        onnotify?.invoke("event triggered!");
    }
}

// 使用
eventpublisher publisher = new eventpublisher();
publisher.onnotify += (msg) => console.writeline(msg);
publisher.triggerevent();

2.linq(language integrated query)

var numbers = new list<int> { 1, 2, 3, 4, 5 };
var even = numbers.where(n => n % 2 == 0).tolist();

对比 java:

3.异步编程(async/await)

public async task downloaddataasync() {
    var client = new httpclient();
    var data = await client.getstringasync("https://example.com");
    console.writeline(data);
}

对比 java:

parallel.invoke(() => {
   // 并行执行cpu密集任务
});

四、常用工具与框架

javac#
maven/gradlenuget(包管理)
spring.net core(框架)
junitxunit/nunit(测试框架)
intellij ideavisual studio / intellij rider(ide)

五、项目结构与命名空间

// 文件:program.cs
using system;
namespace myapplication;

class program {
    static void main(string[] args) {
        console.writeline("hello world!");
    }
}

对比 java:

六、java 到 c# 的常见转换技巧

javac#
system.out.println()console.writeline()
arraylist<t>list<t>
hashmap<k,v>dictionary<k,v>
interfaceinterface
enumenum
try-catch-finallytry-catch-finally

c# 中,反射(reflection) 是一种强大的机制,允许在运行时动态地获取类型信息、创建对象实例、调用方法、访问字段和属性等。对于从 java 转向 c# 的开发者来说,反射的概念是相似的,但 c# 的反射 api 更加简洁、直观,并且与语言特性(如 dynamicnameoflinq)结合更紧密。

七、反射

反射是指在 运行时(runtime) 动态地:

java 与 c# 反射的对比

功能javac#
获取类型对象myclass.classobj.getclass()typeof(myclass)obj.gettype()
获取方法clazz.getmethod("name", params...)type.getmethod("name")
调用方法method.invoke(obj, args)method.invoke(obj, args)
获取属性clazz.getdeclaredfield("name")type.getproperty("name")
获取程序集无直接等价物assembly.getexecutingassembly()
动态创建实例clazz.newinstance()activator.createinstance(type)
动态访问成员通过 field/method 对象通过 propertyinfo/methodinfo

1. 获取type对象

// 通过类型名获取
type type = typeof(string);

// 通过对象获取
object obj = new person();
type type = obj.gettype();

2. 获取类成员信息(属性、方法、字段)

type type = typeof(person);

// 获取所有属性
propertyinfo[] properties = type.getproperties();

// 获取特定方法
methodinfo method = type.getmethod("sayhello");

// 获取所有字段
fieldinfo[] fields = type.getfields();

3. 动态创建实例

object person = activator.createinstance(typeof(person));

4. 调用方法

methodinfo method = type.getmethod("sayhello");
method.invoke(person, null);

5. 访问属性

propertyinfo prop = type.getproperty("name");
prop.setvalue(person, "alice");
string name = (string)prop.getvalue(person);

6. 访问字段(不推荐,除非必要)

fieldinfo field = type.getfield("age", bindingflags.nonpublic | bindingflags.instance);
field.setvalue(person, 30);
int age = (int)field.getvalue(person);

7. 获取程序集信息

assembly assembly = assembly.getexecutingassembly();
foreach (type type in assembly.gettypes()) {
    console.writeline(type.name);
}

8. 动态加载 dll 并调用方法

assembly assembly = assembly.loadfile("path/to/mylibrary.dll");
type type = assembly.gettype("mynamespace.myclass");
object instance = activator.createinstance(type);
methodinfo method = type.getmethod("dosomething");
method.invoke(instance, null);

9. 使用dynamic替代部分反射操作

dynamic person = new expandoobject();
person.name = "bob";
person.sayhello = new action(() => console.writeline("hello"));
person.sayhello(); // 无需反射即可调用

10. 使用expression构建高性能的反射调用

func<object> factory = expression.lambda<func<object>>(
    expression.new(typeof(person))
).compile();
object person = factory();

11. 使用il emit或source generator优化性能

对于高性能场景(如 orm、序列化框架),可以使用:

性能问题

解决方案

安全性

java 到 c# 反射的转换技巧

javac#
class.forname("myclass")type.gettype("mynamespace.myclass")
clazz.newinstance()activator.createinstance(type)
method.invoke(obj, args)method.invoke(obj, args)
clazz.getdeclaredmethods()type.getmethods()
clazz.getdeclaredfields()type.getfields()
clazz.getdeclaredfield("name")type.getfield("name")
clazz.getdeclaredmethod("name", params...)type.getmethod("name", parametertypes)
clazz.getinterfaces()type.getinterfaces()

八、引入包(nuget 包管理)

在 c# 中,nuget 是官方推荐的包管理系统,类似于 java 中的 maven/gradle。它用于管理项目依赖项(如第三方库、框架等)。

nuget 包典型命名规则:[组织名].[功能模块].[平台/框架]

1.nuget 的作用

2.常用方式

方法 1:通过 visual studio 引入

  1. 右键项目 → manage nuget packages
  2. browse 标签页搜索包名(如 newtonsoft.json
  3. 点击 install 安装包
  4. 安装完成后,会自动添加到项目中

方法 2:通过 cli 命令行

# 安装包
dotnet add package newtonsoft.json

# 更新包
dotnet add package newtonsoft.json --version 13.0.1

# 卸载包
dotnet remove package newtonsoft.json

方法 3:手动编辑.csproj文件

在项目文件中添加 <packagereference>

<project sdk="microsoft.net.sdk">
  <propertygroup>
    <targetframework>net6.0</targetframework>
  </propertygroup>

  <itemgroup>
    <packagereference include="newtonsoft.json" version="13.0.1" />
  </itemgroup>
</project>

3.nuget 源配置

默认源是 nuget.org,但也可以配置私有源(如公司内部源):

# 添加私有源
dotnet nuget add source https://mycompany.com/nuget -n mycompany

4.对比 java

功能java (maven/gradle)c# (nuget)
包管理pom.xml / build.gradle.csproj
安装包mvn install / gradle builddotnet add package
私有仓库settings.xml / repositories { maven { url "..." } }dotnet nuget add source

九、引用本地的 dll

有时你需要引用本地的 dll 文件(如团队内部开发的库、第三方未提供 nuget 包的库),可以通过以下方式实现。

1.添加本地 dll 引用

方法 1:通过 visual studio 添加

  1. 右键项目 → add → reference…
  2. 在弹出窗口中选择 browse
  3. 浏览并选择本地 dll 文件(如 mylibrary.dll
  4. 点击 addok

方法 2:手动编辑.csproj文件

<project sdk="microsoft.net.sdk">
  <propertygroup>
    <targetframework>net6.0</targetframework>
  </propertygroup>

  <itemgroup>
    <reference include="mylibrary">
      <hintpath>..\libraries\mylibrary.dll</hintpath>
    </reference>
  </itemgroup>
</project>

2.确保 dll 被正确复制到输出目录

.csproj 中添加以下配置,确保 dll 被复制到 bin 目录:

<contentwithtargetpath include="..\libraries\mylibrary.dll">
  <targetpath>mylibrary.dll</targetpath>
  <copytooutputdirectory>preservenewest</copytooutputdirectory>
</contentwithtargetpath>

3.加载本地 dll 的运行时行为

4.注意事项

常见问题与解决方案

1.无法找到 dll

2.加载 dll 失败

3.版本冲突

十、dllimport(平台调用,p/invoke)

在 c# 中,[dllimport("xxx.dll")]平台调用(platform invocation services,p/invoke) 的核心特性,用于直接调用 非托管代码(如 windows api、c/c++ 编写的 dll)。这是 java 中没有的特性(java 需要通过 jni 调用本地代码)。

1.基本概念

[dllimport]system.runtime.interopservices 命名空间下的特性(attribute),用于声明某个方法的实现来自外部 dll。它允许你在 c# 中直接调用 windows api 或其他非托管函数。

2.使用步骤

步骤 1:引入命名空间

using system.runtime.interopservices;

步骤 2:声明外部方法

使用 [dllimport("dll名称")] 特性修饰方法,指定 dll 名称和调用约定(calling convention)。

[dllimport("user32.dll", charset = charset.auto)]
public static extern int messagebox(intptr hwnd, string text, string caption, uint type);

步骤 3:调用方法

messagebox(intptr.zero, "hello from c#", "greeting", 0);

3.参数说明

参数说明
dllnamedll 文件名(如 "user32.dll"
charset字符集(charset.ansicharset.unicodecharset.auto
callingconvention调用约定(默认为 callingconvention.winapi,也可指定 thiscallstdcall 等)
entrypoint可选,指定 dll 中函数的入口点(当方法名与 dll 函数名不同时使用)

4.常见示例

示例 1:调用user32.dll的messagebox

[dllimport("user32.dll", charset = charset.auto)]
public static extern int messagebox(intptr hwnd, string text, string caption, uint type);

// 调用
messagebox(intptr.zero, "hello from c#", "greeting", 0);

示例 2:调用kernel32.dll的gettickcount

[dllimport("kernel32.dll")]
public static extern uint gettickcount();

// 调用
uint tickcount = gettickcount();
console.writeline($"system uptime: {tickcount} ms");

示例 3:调用gdi32.dll的createdc

[dllimport("gdi32.dll", charset = charset.auto)]
public static extern intptr createdc(string lpszdriver, string lpszdevice, string lpszoutput, intptr lpinitdata);

// 调用
intptr hdc = createdc("display", null, null, intptr.zero);

5.结构体与指针传参

当调用的函数需要结构体或指针参数时,需使用 refoutintptr,并可能需要使用 structlayoutmarshalas 来控制内存布局。

示例:调用user32.dll的getwindowrect

[structlayout(layoutkind.sequential)]
public struct rect
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

[dllimport("user32.dll")]
[return: marshalas(unmanagedtype.bool)]
public static extern bool getwindowrect(intptr hwnd, out rect lprect);

// 使用
rect rect;
bool success = getwindowrect(hwnd, out rect);
if (success)
{
    console.writeline($"window rect: {rect.left}, {rect.top}, {rect.right}, {rect.bottom}");
}

6.注意事项

安全性

平台依赖性

性能

参数封送(marshaling)

7. 示例:封装一个 windows api 工具类

using system;
using system.runtime.interopservices;

public static class win32api
{
    [dllimport("user32.dll", charset = charset.auto)]
    public static extern int messagebox(intptr hwnd, string text, string caption, uint type);

    [dllimport("kernel32.dll")]
    public static extern uint gettickcount();

    [structlayout(layoutkind.sequential)]
    public struct rect
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    [dllimport("user32.dll")]
    [return: marshalas(unmanagedtype.bool)]
    public static extern bool getwindowrect(intptr hwnd, out rect lprect);
}

// 使用
class program
{
    static void main()
    {
        // 调用 messagebox
        win32api.messagebox(intptr.zero, "hello from c#", "greeting", 0);

        // 获取系统运行时间
        uint tickcount = win32api.gettickcount();
        console.writeline($"system uptime: {tickcount} ms");

        // 获取窗口位置
        win32api.rect rect;
        bool success = win32api.getwindowrect(new intptr(0x123456), out rect);
        if (success)
        {
            console.writeline($"window rect: {rect.left}, {rect.top}, {rect.right}, {rect.bottom}");
        }
    }
}

通过掌握 dllimport 和 p/invoke,你可以在 c# 中直接调用 windows api 或其他非托管函数,实现更底层的系统级操作。结合良好的封装和错误处理,可以显著提升程序的功能性和灵活性。

总结

到此这篇关于java快速转c#的文章就介绍到这了,更多相关java快速转c#内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

您想发表意见!!点此发布评论

推荐阅读

Java应对高并发的思路和最佳实践

07-26

Java使用StopWatch输出执行耗时的方法详解

07-26

Spring AI使用tool Calling和MCP的示例详解

07-26

Java Thread中join方法使用举例详解

07-26

springboot使用外置的Servlet容器步骤

07-26

vscode 登录ssh如何记住密码直接登录设置

07-26

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论