{"id":39790,"date":"2020-08-13T06:00:04","date_gmt":"2020-08-13T13:00:04","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/premier-developer\/?p=39790"},"modified":"2020-08-17T06:27:19","modified_gmt":"2020-08-17T13:27:19","slug":"go-and-csharp-comparison","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/go-and-csharp-comparison\/","title":{"rendered":"Go and C# Comparison"},"content":{"rendered":"<p>In this post, App. Dev. Manager <a href=\"https:\/\/www.linkedin.com\/in\/vishalsaroopchand\/\">Vishal Saroopchand<\/a> showcases similarities and differences on important topics for C# developers learning Go.<\/p>\n<hr \/>\n<p>In my <a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/go-from-a-csharp-developer-perspective\/\">previous post<\/a>, I explain my motivation and experience learning Go coming strictly from a C#\/JS background. In this post, I want to update the side-by-side comparison with snippets showing similarities and differences on important topics you will encounter in your Go journey.<\/p>\n<h4>Setup your Development Environment<\/h4>\n<ul>\n<li><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet-core\">Install<\/a> .NET Core<\/li>\n<li><a href=\"https:\/\/golang.org\/doc\/install\">Install<\/a> Go<\/li>\n<li><a href=\"https:\/\/code.visualstudio.com\/download\">Install<\/a> an editor such as VSCode<\/li>\n<li>Go <a href=\"https:\/\/code.visualstudio.com\/docs\/languages\/go\">tools<\/a> for VSCode<\/li>\n<\/ul>\n<h4>Program Structure<\/h4>\n<pre class=\"prettyprint\">\/\/ main.go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"os\"\r\n)\r\n\r\nfunc main(){\r\n\r\n\t\/\/ args\r\n\tfor i, arg := range os.Args {\r\n\t\tfmt.Println(fmt.Sprintf(\"Arg %s at index %v\", arg, i))\r\n\t}\r\n\r\n\tfmt.Println(\"Press ENTER to continue\")\r\n\tfmt.Scanln()\r\n}\r\n\r\nfunc init(){\r\n\tfmt.Println(\"Initializer\")\r\n}\r\n<span style=\"color: #52595e; font-family: Arimo, 'Helvetica Neue', Arial, sans-serif; font-size: 1rem;\">\r\nNote: Check out C# <\/span><a style=\"background-color: #f7f7f9; font-family: Arimo, 'Helvetica Neue', Arial, sans-serif; font-size: 1rem;\" href=\"https:\/\/github.com\/dotnet\/command-line-api\">CommandLine<\/a><span style=\"color: #52595e; font-family: Arimo, 'Helvetica Neue', Arial, sans-serif; font-size: 1rem;\"> API and <a href=\"https:\/\/github.com\/spf13\/cobra\">Cobra<\/a> for Go. Both offer enhancements for CLI apps.<\/span>\r\n<\/pre>\n<h4>Type Declarations<\/h4>\n<pre class=\"prettyprint\">\/\/ go\r\npackage models\r\n\r\n\/\/ Student is a student object\r\ntype Student struct {\r\n\tID int\r\n\tFirstName string\r\n\tLastName string\r\n\tAge int\r\n}\r\n\r\n\/\/ NewStudent is a constructor function that will return a Student pointer\r\nfunc NewStudent(firstName string, lastName string, age int) *Student {\r\n\treturn &amp;Student{\r\n\t\tFirstName : firstName,\r\n\t\tLastName : lastName,\r\n\t\tAge: age,\r\n\t}\r\n}<\/pre>\n<pre class=\"prettyprint\">\/\/ c#\r\nnamespace School.Models\r\n{\r\n    public class Student\r\n    {\r\n        public int Id { get; set; }\r\n        public string FirstName { get; set; }\r\n        public string LastName { get; set; }\r\n        public int Age { get; set; }\r\n        \r\n        public Student(){}\r\n        public Student(string firstName, string lastName, int age)\r\n        {\r\n            this.FirstName = firstName;\r\n            this.LastName = lastName;\r\n            this.Age = age;\r\n        }\r\n    }\r\n}<\/pre>\n<h4>Functions<\/h4>\n<pre class=\"prettyprint\">\/\/ go\r\n\/\/ NewStudent is a constructor function that will return a Student pointer\r\nfunc NewStudent(firstName string, lastName string, age int) *Student {\r\n\treturn &amp;Student{\r\n\t\tID : 0,\r\n\t\tFirstName : firstName,\r\n\t\tLastName : lastName,\r\n\t\tAge: age,\r\n\t}\r\n}\r\n\r\n\/\/ Enroll student into a class\r\nfunc(s *Student) Enroll(c Class) error {\r\n\treturn c.Add(s)\r\n}<\/pre>\n<p>Important differences:<\/p>\n<ul>\n<li><strong>NewStudent<\/strong> is a constructor function, as such it does not have a receiver (pointer or value).<\/li>\n<li><strong>Enroll<\/strong> is bound to a pointer receiver *Student<\/li>\n<li><strong>Add<\/strong> is bound to a value receiver on struct Class<\/li>\n<li>No access modifiers in Go, uppercase denotes <strong>public<\/strong> and lowercase <strong>private<\/strong> (only accessible within type or package (unbound))<\/li>\n<\/ul>\n<p>C#<\/p>\n<p>Methods in C# has the following structure. See the official <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/methods\">docs<\/a> for more information.<\/p>\n<pre class=\"prettyprint\">AccessModifier unsafe\/static\/virtual\/override\/async ReturnType MethodName(Type param1, Type out param2, ref Type param3, params int[] param4) \r\n{\r\n   \/\/Method Body\r\n<\/pre>\n<pre class=\"prettyprint\"><\/pre>\n<p>See C# Language specs on keywords:<\/p>\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/access-modifiers\" data-linktype=\"relative-path\">Access Modifiers<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/static-classes-and-static-class-members\" data-linktype=\"relative-path\">Static Classes and Static Class Members<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/inheritance\" data-linktype=\"relative-path\">Inheritance<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/abstract-and-sealed-classes-and-class-members\" data-linktype=\"relative-path\">Abstract and Sealed Classes and Class Members<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/keywords\/params\" data-linktype=\"relative-path\">params<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/keywords\/return\" data-linktype=\"relative-path\">return<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/keywords\/out\" data-linktype=\"relative-path\">out<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/keywords\/ref\" data-linktype=\"relative-path\">ref<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-7#tuples\">tuple return type<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/passing-parameters\" data-linktype=\"relative-path\">Passing Parameters<\/a><\/li>\n<\/ul>\n<h4>Type conversations<\/h4>\n<pre class=\"prettyprint\">\/\/ go\r\nfunc exporeTypeConversions() {\r\n\t\/\/ use strconv to parse string to int64\r\n\ti, _ := strconv.ParseInt(\"-42\", 10, 64)\r\n\t\/\/ explict conversion of int to float\r\n\tf := float32(i)\r\n\t\/\/ convert float to string\r\n\ts := fmt.Sprintf(\"%f\", f)\r\n\r\n\tfmt.Println(fmt.Sprintf(\"i = %v, f = %f, s = %s\", i, f, s))\r\n\r\n\t\/\/ use i.(type) with switch statement, or string format %T\r\n\ttestType := func(i interface{}) string {\r\n\r\n\t\tswitch i.(type) {\r\n\t\tcase int:\r\n\t\t\treturn \"int64\"\r\n\t\tcase string:\r\n\t\t\treturn \"string\"\r\n\t\tdefault:\r\n\t\t\treturn fmt.Sprintf(\"%T\", i)\r\n\t\t}\r\n\t}\r\n\r\n\tfmt.Println(testType(i))\r\n\tfmt.Println(testType(s))\r\n\tfmt.Println(testType(models.NewStudent(\"\", \"\", 18)))\r\n}<\/pre>\n<pre class=\"prettyprint\">\/\/ c#   \r\n     static void Main(string[] args)\r\n        {                        \r\n            int a = 64;\r\n            \/\/ implicit\r\n            long b = a;\r\n            \/\/ explicit\r\n            int c = (int) b;\r\n\r\n            \/\/ use (Type is Target TempReceiver)\r\n            if( c is int d){\r\n                \/\/\r\n            }\r\n          \r\n           \/\/ use typeof(T)\r\n           Console.WriteLine(<span class=\"hljs-keyword\">typeof<\/span>(List&lt;<span class=\"hljs-keyword\">string<\/span>&gt;));\r\n        }<\/pre>\n<h4>Error Handling<\/h4>\n<p>Go lacks C# formal pattern (try, catch, finally) for error handling. The best practice for go is to return a error type as the last return value which the caller can test for an error condition.<\/p>\n<pre class=\"prettyprint\">\ts := models.Student{\r\n\t\tFirstName: \"Jake\",\r\n\t}\r\n\tc := models.Class{\r\n\t\tName: \"Computer Science\",\r\n\t}\r\n\terr := s.Enroll(c)\r\n\r\n\tif err != nil {\r\n\t\tlog.Fatalf(\"Error enrolling student %s in class %s\", s.FirstName, c.Name)\r\n\t}\r\n\r\n\t\/\/otherwise, continue...<\/pre>\n<h4>Interface<\/h4>\n<pre class=\"prettyprint\">\/\/ go\r\ntype DataRepository interface {\r\n\tAdd(s *Student) (error)\r\n\tUpdate(s *Student) (error)\r\n\tGet(id int) (*Student, error)\r\n\tDelete(id int) (error)\r\n}<\/pre>\n<pre class=\"prettyprint\">\/\/ c#\r\npublic interface IDataRepository&lt;T&gt;\r\n{\r\n    void Add(T s);\r\n    void Update(T s);\r\n    T Get(int id);\r\n    void Delete(int id);\r\n}<\/pre>\n<p>Notes:<\/p>\n<ul>\n<li>C# best practice is to use Generics to define interface templates.<\/li>\n<li>Due to the lack of a formal exception handling (try, catch, finally), we must return an error in Go for error conditions.<\/li>\n<li>Avoid using &#8220;I&#8221; as prefix in your Go interface names.<\/li>\n<li>Go is duck typing while C# requires explicit implementation of the interface.<\/li>\n<\/ul>\n<h4>Inheritance<\/h4>\n<pre class=\"prettyprint\">\/\/ go\r\ntype DataReaderWriter interface {\r\n\tio.Reader\r\n\tio.Writer\r\n}\r\n\r\ntype DataWriterReaderImpl struct {\r\n}\r\n\/\/ implements io.Reader\r\nfunc (dwr DataWriterReaderImpl) Read(p []byte) (n int, err error) {\r\n\t\/\/\r\n\treturn 0, nil\r\n}\r\n\r\n\/\/ implements io.Writer\r\nfunc (dwr DataWriterReaderImpl) Write(p []byte) (n int, err error) {\r\n\t\/\/\r\n\treturn 0, nil\r\n}<\/pre>\n<p>Sample use of DataWriterReaderImpl in Go<\/p>\n<pre class=\"prettyprint\">\tbuffer := new(bytes.Buffer)\r\n\tjson.NewEncoder(buffer).Encode(models.Student{})\r\n\r\n\tdwr := models.DataWriterReaderImpl{}\r\n\t\/\/ you can cast to an io.Writer, for example, pass to func by interface type\r\n\ttest := io.Writer(dwr)\r\n\t\/\/ call write\r\n\t_, err := test.Write(buffer.Bytes())\r\n\tif err != nil {\r\n\t\tlog.Fatal(\"Error invoking writer\")\r\n\t}<\/pre>\n<p>Here is our C# implementation to show the similarities and differences for an similar type.<\/p>\n<pre class=\"prettyprint\">    public interface IWriter\r\n    {\r\n        public int Write(byte[] p);\r\n    }\r\n\r\n    public interface IReader\r\n    {\r\n        public byte[] Read();\r\n    }\r\n    public interface IDataReaderWriter : IWriter, IReader\r\n    {\r\n    }\r\n    public class DataReaderWriterImpl : IDataReaderWriter\r\n    { \r\n        public int Write(byte[] p){\r\n            \/\/\r\n            return 0;\r\n        }            \r\n\r\n        public byte[] Read(){\r\n            \r\n            return System.Text.Encoding.UTF8.GetBytes(\"Hello\");\r\n        }   \r\n    }<\/pre>\n<p>Notes:<\/p>\n<ul>\n<li>C# requires explicit implementation while Go is implicit (duck typing)<\/li>\n<\/ul>\n<h4>Concurrency<\/h4>\n<pre class=\"prettyprint\">\/\/ go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"sync\"\r\n\t\"time\"\r\n)\r\n\r\nfunc main() {\r\n\r\n\tvar wg sync.WaitGroup\r\n\twg.Add(2)\r\n\r\n\tgo func() {\r\n\t\t\/\/ simulate work\r\n\t\ttime.Sleep(10 * time.Second)\r\n\t\tfmt.Println(\"Job1 completed\")\r\n\t\twg.Done()\r\n\t}()\r\n\r\n\tgo func() {\r\n\t\t\/\/ simulate work\r\n\t\ttime.Sleep(5 * time.Second)\r\n\t\tfmt.Println(\"Job2 completed\")\r\n\t\twg.Done()\r\n\t}()\r\n\r\n\twg.Wait()\r\n\r\n\tfmt.Println(\"Done\")\r\n}<\/pre>\n<p>For comparison, here is our C# sample using System.Threading to dispatch new threads.<\/p>\n<pre class=\"prettyprint\">            \/\/ old way of dispatching threads\r\n            var t1 = new Thread(() =&gt; {\r\n                Thread.Sleep(5);\r\n                Console.WriteLine(\"Job1 completed\");\r\n            });\r\n\r\n            var t2 = new Thread(() =&gt; {\r\n                Thread.Sleep(5);\r\n                Console.WriteLine(\"Job2 completed\");\r\n            });\r\n\r\n            t1.Start();\r\n            t2.Start();\r\n           \r\n            \/\/ new &amp; preferred approach for concurrency \r\n            var t3 = new Task(() =&gt; {\r\n                Thread.Sleep(5);\r\n                Console.WriteLine(\"Job3 completed\");\r\n            });\r\n            t3.Start();\r\n\r\n            var t4 = Task.Run(() =&gt; {\r\n                Thread.Sleep(5);\r\n                Console.WriteLine(\"Job4 completed\");\r\n            });\r\n\r\n            Task.WaitAll(t3, t4);\r\n<\/pre>\n<p>Notes:<\/p>\n<ul>\n<li>Use go-routines (<strong>go<\/strong> func()) to start new threads in Go.<\/li>\n<li>Go-routines don&#8217;t bock, you just use sync.WaitGroup or channels to signal.<\/li>\n<li>C# uses System.Threading or System.Threading.Task to dispatch new threads.<\/li>\n<li>Use CancellationToken to cancel\/signal, see <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/asynchronous-programming-patterns\/consuming-the-task-based-asynchronous-pattern\">docs<\/a>.<\/li>\n<\/ul>\n<p>There is much more to compare, but I hope this gives you a taste of Go as you start your own journey with the language.<\/p>\n<p class=\"x-hidden-focus\">References:<\/p>\n<ul>\n<li><a href=\"https:\/\/golang.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/golang.org\/<\/a><\/li>\n<li class=\"x-hidden-focus\"><a href=\"https:\/\/golang.org\/pkg\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/golang.org\/pkg\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this post, App. Dev. Manager Vishal Saroopchand showcases similarities and differences on important topics for C# developers learning Go.<\/p>\n","protected":false},"author":582,"featured_media":37840,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[80,6699,4612,129,1],"tags":[116,40],"class_list":["post-39790","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-c","category-community","category-premier","category-permierdev","tag-c","tag-development"],"acf":[],"blog_post_summary":"<p>In this post, App. Dev. Manager Vishal Saroopchand showcases similarities and differences on important topics for C# developers learning Go.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/39790","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=39790"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/39790\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=39790"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=39790"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=39790"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}