CSharp Similarities and Differences
This document lists some basic differences between Nemerle and C# in a terse form. If you know Java or C++ it should still be fairly helpful.
Changes In Expressions
C# | Nemerle | Remarks |
---|---|---|
const int x = 3; const string y = "foo"; readonly Object obj = getObject(); |
def x : int = 3; def y : string = "foo"; def obj : Object = getObject(); |
Variables defined with def cannot be changed once defined. This is similar to readonly or const in C# orfinal in Java. Most variables in Nemerle aren't explicitly typed like this. |
int x = 3; string y = "foo"; Object obj = getObject(); |
mutable x : int = 3; mutable y : string = "foo"; mutable obj : Object = getObject(); |
Variables defined with mutable can be changed once defined. Most variables in Nemerle aren't explicitly typed like this. |
var = 3; //Will compile. var y; y = "foo";//Won't compile. |
def = 3;//Will compile! mutable y; y = "foo";//Will compile! |
Nemerle's type inference is lightyears ahead of C#'s. If there is clear evidence of a variable's type, there's a 99% chance Nemerle will infer it. |
int a = b = c; |
def a = c; def b = c; |
The type of the assignment operator is void. |
value = cond ? var1 : var2; |
value = if(cond) var1 else var2 |
No ternary operator is needed as everything is an expression in Nemerle. The 'else' branch is mandatory here! (Don't panic! if-without-else has its own keyword.) |
Class myClass = new Class(parms); |
def myClass = Class(parms); |
Nemerle doesn't require new when calling a constructor. |
Book[] books = new Book[size]; |
def books = array(size) : array[Book]; |
Often the array type can be inferred and this is simplified; as in the next example. |
Book[] books = new Book[size]; books[0] = new Book(); |
def books = array(size); books[0] = Book(); |
When the type can be inferred from context or later use (which is most of the time), you can drop the type declaration |
int[] numbers = {1, 2, 3}; |
def numbers = array[1, 2, 3]; |
Initializing an array. Without the array keyword this would create a list. |
int[,] numbers = new int[2,3]; |
def numbers = array(2,3) : array.[2][int]; |
Multidimensional array constructor. The type can usually be inferred from use and not declared. |
int[,] numbers = { {1,2,3}, {1,4,9} }; |
def numbers = [ [1,2,3], [1,4,9] ]; |
Multidimensional array initialization. |
new {Prop1 = 1; Prop2 = "string"} |
using Nemerle.Extensions; new (Prop1 = 1, Prop2 = "string") |
Nemerle anonymous typesare a bit more flexible (e. g. can be generic or returned from a method). They must be imported from Nemerle.Extensions however. |
new Class { Property1 = 1; Property2 = "string" } |
Class() |
The Nemerle Object Modifier macro is more powerful. |
if(cond) answer = 42; ... |
when(cond) answer = 42; ... |
if without else is called when . Nemerle requiresif statements to be paired with else for clarity. |
if(!cond) answer = 42; ... |
unless(cond) answer = 42; ... |
In Nemerle,if(!cond) can use the clearerunless(cond) syntax. Of course,when(!cond) can also always be used. |
if (cond) return foo; do_something (); return bar; |
match(cond){ | true => foo | _ => {doSomething(); foo} } |
Pattern Matchingprovides a clearer way of delegating control flow. |
if (cond) return foo; do_something (); return bar; |
using Nemerle.Imperative; when(cond) return foo do_something (); return bar; |
Alternately the Imperative namespace may be imported. This isdiscouragedhowever. |
try {...} catch (FooException e) { ... } catch (BarException e) { ... } |
try {...} catch { | e is FooException => ... | e is BarException => ... } |
Nemerle's somewhat differenttry ... catch syntax is consistent with its pattern matching syntax. |
(type) expr |
expr :> type |
Runtime type cast, allows for downcasts and upcasts. |
(type) expr |
expr : type |
Static cast, only upcasts are allowed. |
using System; using SWF = System.Windows.Forms; using System.Xml; ... Console.WriteLine ("foo"); SWF.Form x = new SWF.Form(); XmlDocument doc = new XmlDocument(); |
using System; using System.Console; using SWF = System.Windows.Forms; ... WriteLine("foo"); def x = SWF.Form(); def doc = Xml.XmlDocument(); |
In Nemerle, you can apply the using directive to classes as well as namespaces. Opened namespaces allow you to drop the prefix of other namespaces, likeSystem inSystem.Xml . More info. |
using System.Windows.Forms; Button button = control as Button; if (button != null) ... else ... |
match (control) { | button is Button => ... | listv is ListView => ... | _ => ...//something else } |
as can be simulated withmatch . It is a bit more to type up in simple cases, but in general Nemerle's construct is more powerful. |
int y = x++; ++x; |
def y = x; x++; ++x; |
The ++ and -- operators return void, just like assignment. So, both prefix and postfix versions are equivalent. |
Changes In Type Definitions
C# | Nemerle | Remarks |
---|---|---|
static int foo (int x, string y) { ... } |
static foo (x : int, y : string) : int { ... } |
Types are written after variable names. |
class Foo { public Foo (int x) { ... } } |
class Foo { public this (x : int) { ... } } |
The constructor's name is alwaysthis . |
class Foo { ~Foo () { ... } } |
class Foo { protected override Finalize () : void { ... } } |
There is no special syntax for the destructor, you just override theFinalize method. |
class Foo : Bar { public Foo (int x) : base (x) { ... } } |
class Foo : Bar { public this (x : int) { base (x); ... } } |
The base constructor is called in the constructor's function body. |
class Foo { int x; } |
class Foo { mutable x : int; } |
Fields which will be changed outside of the constructor need to be marked asmutable . |
class Foo { readonly int x; const int y = 10; } |
class Foo { x : int; y : int = 10; } |
Read-only/const are used by default. |
class Foo { static int x = 1; } |
class Foo { static mutable x : int = 1; } |
Static variable. |
class Foo { static readonly int x; static int method() { ... } } |
module Foo { x : int; method() : int { ... } } |
A module is a class in which all members are static. |
using System.Runtime.CompilerServices.CSharp; class C { public object this [int i] { ... } [IndexerName("MyItem")] public int this [string name] { ... } } |
class C { public Item [i : int] : object { ... } public MyItem [name : string] : int { ... } } |
Indexers. |
C# | Nemerle |
---|---|
When two interfaces use the same method to perform different functions, different names can be given to each method. | |
interface SpeaksEnglish{ void Speak(); } interface SpeaksGerman{ void Speak(); } class GermanTransfer : SpeaksEnglish, SpeaksGerman{ public void SpeaksEnglish.Speak() {} public void SpeaksGerman.Speak() {} } |
interface SpeaksEnglish{ Speak() : void; } interface SpeaksGerman{ Speak() : void; } class GermanTransfer : SpeaksEnglish, SpeaksGerman{ public Speak() : void implements SpeaksEnglish.Speak{} public Sprechen() : void implements SpeaksGerman.Speak{} } |
Generics
C# | Nemerle | Remarks |
---|---|---|
class A { T x; } |
class A [T] { x : T; } |
Type parameters are written in square brackets [...]. |
typeof(A); |
typeof(A[_,_]); |
typeof expression |
New Stuff
Nemerle contains many constructs which are not present in C#. Unfortunately, most of them don't really fit into a side-by-side comparison format:
- Tuples -- a nameless, heterogeneous data structure.
- Lists -- a special syntax for lists and list processing.
- The Void Literal -- a useful construct for recursive functions.
- Local functions -- defining functions within other functions.
- Functional Values -- passing functions as arguments and returning them from other functions.
- Anonymous Functions -- defining functions which don't need names.
- Variants and Pattern Matching -- an alternative, and very useful, control flow construct.
- Macros -- writing code that writes code.
Other Minor Differences
Ambiguity Isn't Tolerated
namespace YourAttributes{
class Serializable : System.Attribute { }
}
namespace MyAttributes{
using YourAttributes;
class Serializable : System.Attribute { }
[Serializable] class SomeClass { }
}
C# compilers will choose MyAttributes.Serializable or, if its definition is commented out, YourAttributes.Serializable. Nemerle will raise an error telling you to be more specific about which attribute you want to use.
Exclusion of Overridden Methods
class BaseClass
{
public virtual AddItem (val : string) : void { }
}
class TestClass : BaseClass
{
public AddItem (val : object) : void { }
public override AddItem (val : string) : void { }
}
...
TestClass().AddItem ("a"); // C# will choose TestClass.AddItem (object)
// Nemerle will choose TestClass.AddItem (string)
This behaviour comes from section 7.6.5.1 of the C# specification, which states "...methods in a base class are not candidates [for overload resolution] if any method in a derived class is applicable (§7.6.5.1)." Unfortunately, this rule is patently absurd in situations like the above. The Nemerle compiler always chooses the method whose signature best matches the given arguments.
XAF开发成品案例参考
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
作者博客: http://www.cnblogs.com/foreachlife
欢迎加入CIIP框架\XAF技术应用交流群: 336090194 群文件中有更多相关工具及文档资料
转载请注明出处。多谢!
欢迎加我微信: admiralcn 或扫码:

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端