以Java8的视角看C#
语法层面
在许多方面,C# 语法读起来像是 Java 语法的超集,但是有一些重命名和新增的关键字。
- 命名规范
用Pascal规则来命名属性、方法、事件, 类名和命名空间
public class HelloWorld { public void SayHello(string name) {} }用Camel规则来命名成员变量、局部变量和方法的参数
public class Product { private string productId; private string productName; public void AddProduct(string productId,string productName){} }
函数返回值
C# tuple
可以通过tuple返回多个值
public static (string, string)
SplitAt(this string s, int at)
=> (s.Substring(0, at), s.Substring(at));
var (baseCcy, quoteCcy) = "EURUSD".SplitAt(3);
Console.WriteLine(baseCcy);
Console.WriteLine(quoteCcy);
可以起个有意义的名字
public static (string, string)
SplitAt(this string s, int at)
=> (s.Substring(0, at), s.Substring(at));
public static (string Base, string Quote)
AsPair(this string ccyPair) => ccyPair.SplitAt(3);
var pair = "EURUSD".AsPair();
Console.WriteLine(pair.Base);
Console.WriteLine(pair.Quote);
工程组织和工具
Java
组织工具
Maven已经成为了事实上的标准. pom.xml是整个项目的定义
- 依赖的包
- 编译管理
- 插件
- 自动测试
- 项目模板
工程组织
- 每个项目都是单独的pom.xml文件
- 本地的多个项目使用上层依赖工具管理, 比如make
c#
组织工具
dotent是事实标准
- 和nuget一起管理包依赖
- 编译管理
- 插件, 比如 dotnet script
- 项目模板
- 单元测试
工程组织
solution 项目的Visual Studio 解决方案文件格式(.sln), 是项目的容器 结构上分为三层 1. 版本信息 2. 项目信息 3. 全局信息 参照此文章
Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 25.0.1704.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyNunit", "MyNunit.csproj", "{FE7951F6-8BAC-4198-A3F1-06648FE444C3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {FE7951F6-8BAC-4198-A3F1-06648FE444C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE7951F6-8BAC-4198-A3F1-06648FE444C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {FE7951F6-8BAC-4198-A3F1-06648FE444C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE7951F6-8BAC-4198-A3F1-06648FE444C3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C7B7CCE4-CEB3-4DDF-9279-0DDC617EAD51} EndGlobalSection EndGlobalproject
代码组织
命名控件(namespace) vs 包(package)
引入类型
java: import
import class/classes 引入一个包中的全部类型(type), 或者某个类型
import java.util.*; import java.util.Date;static import 引入类的所有静态成员
import static java.lang.Math.PI; import static java.lang.Math.*; System.out.println("hahah "+ PI);
C# using using的含义比import丰富
引入一个命名空间(namespace)
using System; Console.WriteLine("hello");C# using static 作用于某一个Type(意思是此Type的static(静态类型)可以被直接使用.
using static System.Console; WriteLine("hello");别名 using x =
using Unit = System.ValueTuple; public Func<Unit> ToFunc ( Action action) => () => { action(); return default; }; public Func<T, Unit> ToFunc<T> ( Action<T> action) => (t) => { action(t); return default; };
Delegate vs ??
C#
| C# type | function type | Example |
|-----------------------|--------------------|---------------------------|
| Func <int, String > | int- >string | (int i) = > i.ToString() |
| Func <string > | ()- > string | () = > "hello" |
| Action <int > | int- >() | (int i)= >WriteLine(i) |
| Func <int, int, int > | (int, int) = > int | (int a, int b) = > a + b |
| Action | ()- >() | () = > WriteLine("hello") |
举例
Delegate是一个C#类型, 代表了一个对象方法(method)的引用(reference), 在Java中我(暂时)没有找到对应物. 它更像个C的函数指针. 它有一个参数列表(0个或者多个参数), 有一个返回类型(可以是void).
Delegate可以指向任意一个符合其函数签名的method.
public class Calc{ public delegate int Calculate(int input); public int Execute(Calculate calcuate, int input){ return calcuate(input); } } public class Program{ public static int Square(int input) => input * input; } var calculator = new Calc(); Calc.Calculate calc = Program.Square; var result = calculator.Execute(calc, 5); Console.WriteLine($"result:{result}");Action和Func
Delegate从返回值的类型来说, 可分为两类1. 有返回值的 2. 无返回值的 有了Action和Func, 我想不到我们有任何自己声明Delegate的必要性.
Func
有16中可能的参数组合 Func <T, TResult >, Func <T1, T2, TResult >, Func <T1, T2… T16, TResult > public class Calc{ public int Execute(Func<int, int> calcuate, int input){ return calcuate(input); } } public class Program{ public static int Square(int input) => input * input; } var calculator = new Calc(); var result = calculator.Execute(Program.Square, 5); Console.WriteLine($"result:{result}");Action
, 同样的, 也可以有16个参数, 但是不返回值 Action , Action <T1, T2 >, Action <T1, T2… T16 > public class Calc{ public int Execute(Func<int, int> calcuate, Action<int> print, int input){ var result = calcuate(input); print(result); return result; } } public class Program{ public static int Square(int input) => input * input; } var calculator = new Calc(); var result = calculator.Execute(Program.Square, System.Console.WriteLine, 5);Predicate
也是一种Delegate类型, 等价于 Func <T, bool >. 但是从语意上更明确.
Lambda
匿名函数, 所有的Delegate可以用lambda来表示, 而且可以是async的
public class Calc{ public int Execute(Func<int, int> calcuate, int input){ return calcuate(input); } } var calculator = new Calc(); var result = calculator.Execute(x => x * x; , 5); Console.WriteLine($"result:{result}");lambda的形式
(input-parameters) = > expression 直接返回表达式的值
(input-parameters) = > {
} 如果有返回值需要return 最简单的lambda形式
var f = () => "kevin"; Console.WriteLine(f());
event
用来出发一个delegate的执行, delegate在这种情况下被成为一个callback, 这个callback有两个参数 第一个是参数是事件的发出者, 第二个是event的类型.
public class Calc{ public int Execute(Func<int, int> calcuate, int input){ return calcuate(input); } } var calculator = new Calc(); var result = calculator.Execute((x) => x * x , 5); Console.WriteLine($"result:{result}");
Java 8
| Interface name | Arguments | Returns | Example |
|---------------------|-----------|---------|------------------------------------|
| Predicate <T > | T | boolean | Has this album been released yet? |
| Consumer <T > | T | void | Printing out a value |
| Function <T,R > | T | R | Get the name from an Artist object |
| Supplier <T > | None | T | A factory method |
| UnaryOperator <T > | T | T | Logical not (!) |
| BinaryOperator <T > | (T, T) | T | Multiplying two numbers ( *) |
Annotation vs Attribute
都是元数据, 可以作用于class或者class的property以及method
常见的Attribute有 [Serializable] 实现方式就是个类, 类名称
XXXAttribute , 属性为 [XXX]
[Test("Attribute Test", Quantity = 10)]
internal class AttributeExample{}
public class TestAttribute : Attribute {
private readonly string name;
public int Quantity;
public TestAttribute(string name){
this.name = name;
}
public string Name () => name;
}
// 可以在运行时拿到
var attributes = typeof(AttributeExample).GetCustomAttributes(true);
foreach(var att in attributes){
var attValue = (TestAttribute)att;
Console.WriteLine($"name {attValue.Name}, Quantity: {attValue.Quantity}");
}
类型层级
- Java: 所有类都是java.lang.Object的子类
- C#: 所有类都是System.Object的子类
资源管理: IDisposable vs Closeable
保证资源一定会释放掉, 各类语言都逐渐增加了try-with-resources的模式, 本质就是(自动)释放资源
C#
using (var connection = new SqlConnection(connectionString)) { ... }
会被编译为:
try {
var connection = new SqlConnection(connectionString);
...
} finally {
connection.Dispose();
}
Java
Java1.7增加了AutoClosable接口
try(Resource resource = new Resource()) {
resource.read();
} catch (Exception e) {
}
Clojure
(with-open [r (clojure.java.io/input-stream "myfile.txt")]
(loop [c (.read r)]
(if (not= c -1)
(do
(print (char c))
(recur (.read r))))))
Struct
C#中的struct对应c语言中的struct,直接对应内存结构, 没有元数据, 但是也区别于c的结构体(struct), 这个C#的struct只能分配在堆上. 对应于C#中函数传值的(传入/传出)的场景,如果是struct, 只会返回value, 而class的实例是引用(reference)
- Java没有Struct
stream vs linq
java
import java.util.stream.*;
import java.util.*;
Set<Integer> numbers = new HashSet<>(Arrays.asList(4, 3, 2, 1));
System.out.println(numbers);
代码组织
- 库函数.jar vs .dll
- 代码文件和package vs namespace
- sln/proj vs pom.xml