Pages: [1]   Go Down
Print
Author Topic: What is new in C# 4.0  (Read 484 times)
0 Members and 1 Guest are viewing this topic.
Miolynet
Moderator
เกรียนในตำนาน
*****
Offline Offline

Gender: Male
Posts: 645

( หม่าวๆ ~ แหม่วๆ )


View Profile
« on: July 27, 2009, 08:26:41 PM »

What is new in C# 3.0

เอาละเว้ยยยย . . . มา ละ หว่าาาาาา ขออภัยด้วยหากเพื่อนๆทราบข้อมูลนี้กันแร้ว แต่พอดีเห็นยังไม่มีใครโพสต์ อูเลยขอเจิมซะหน่อย

ข่าวคราวการมาของ Visual Studio version 2010 !! มันมาได้ราวๆเดือนกว่าละ (ช่วงนั้นเน็ทเดี้ยง)
 - เอาละหลังจากราวๆปีก่อนนี้เองอูได้โพสต์ Features ของ C# version 3.0 ไว้ ปีต่อมา 2009 Microsoft ก้ได้คลอดตัวใหม่ของ .Net ออกมา 4.0 เรามาดูกันดีกว่าว่ามีอะไรเพิ่มเติมกันบ้าง

[ปล.ขี้เกียจแปล ไปอ่านกันเองง่ายอยู่แล้ว]


Credit : http://www.bloggang.com/viewblog.php?id=chaowman&date=16-03-2009&group=1&gblog=17

ประวัติของ C#
C# 1.0 - คือ จุดเริ่มต้นของภาษา C แบบ Managed Code ซึ่งทำให้การเขียน Code ปลอดภัยและไม่ซับซ้อน ไม่ต้องยุ่งกับ Memory
C# 2.0 - เพิ่ม Generics (และ features อีกมากมาย) ทำให้ Collections ต่าง ๆ Type Safety และมีประสิทธิภาพ
C# 3.0 - Version ปัจจุบัน เพิ่ม LINQ ทำให้เราสามารถ Query Collections ต่าง ๆ ง่ายดาย
และ C# 4.0 - คือยุคของ Dynamic Programming ซึ่งจะพูดถึงต่อไป

แนวโน้มของภาษา
Declarative - คือ แค่บอกว่าจะทำอะไร ไม่ต้องระบุว่าจะทำอย่างไร เช่น LINQ แค่สั่ง orderby ไม่ต้องเขียน for-loop
Dynamic - เพื่อให้ทำงานร่วมกับภาษา Dynamic ต่าง ๆ เช่น Python, Ruby, JavaScript, และ COM
Concurrency - ปกติการเขียน Code แบบ Muti-Thread จะยุ่งยาก แต่ Parallel Library จะจัดการส่วนที่ยุ่งยากให้

สิ่งใหม่ ๆ ใน C# 4.0
Dynamic Language Support
Feature ชูโรงของ C# 4.0
Static Type คือ การกำหนด Type และกำหนด Method ต่าง ๆ ตอน Compile ทำให้ Application มีประสิทธิภาพ
แต่ Dynamic Type จะกำหนด Type และ Method ที่ใช้ตอน Runtime ซึ่งมีข้อดีคือเขียนง่าย เร็ว
C# 4.0 บอกว่าต่อไปนี้เราจะมี Type พิเศษ คือ dynamic
ถ้า object ไหนเป็น dynamic ก็จะเรียก Method, Property, หรือ Index อะไรก็ได้ เช่น

dynamic d = GetDynamic();
d.Foo();

Object "d" อาจไม่มี method ชื่อ Foo ก็ได้ แต่จะ Compile ผ่านเสมอ
มีประโยชน์ เช่น App ของ SilverLight เวลาไปคุยกับ JavaScript
ทำให้ SilverLight สามารถเรียกคำสั่งต่าง ๆ ใน JavaScript ได้เลย
(ใน Demo จะมีการเลือกชื่อ Contact ใน SilverLight
แล้วตอนเลือก .Net จะเรียกคำสั่งดึงข้อมูล Map ผ่าน JavaScript
แล้วเอาข้อมูลของ Map นั้นมาแสดงใน SilverLight)

Optional and Named Parameters
เป็น Feature ล้าหลังมาก ซึ่ง VB.NET มีตั้งแต่ Version แรกแล้ว
ปกติเราจะเขียน Method นึงที่รับหลาย ๆ parameter
แต่บาง parameter มี default value ซึ่งไม่ต้องใส่ก็ได้
ก่อนหน้านี้เราต้องทำ method overloading สร้าง method หลาย ๆ ตัว เช่น

public void MyMethod(string name, string location) {
    Console.WriteLine("Name is {0}, Location is {1}", name, location);
}
public void MyMethod(string name) {
    MyMethod(name, "Bangkok");
}

แต่ Optional Parameter ทำให้เราเขียนแบบนี้ได้เลย

public void MyMethod(string name, string location = "Bangkok") {
    Console.WriteLine("Name is {0}, Location is {1}", name, location);
}

COM Interoperability
การทำงานกับ COM เขียนง่ายขึ้น หลัก ๆ ก็มาจาก dynamic และ named parameters
และเพิ่มว่าไม่ต้องใส่ ref missing อีกต่อไป เช่น

obj.Foo(ref missing, ref missing,
        ref missing, ref missing,
        5, ref missing,
        ref missing, ref missing);

เป็น

obj.Foo(fooID: 5);

จะเห็นว่าเขียนง่ายขึ้นเยอะ

Co- and Contra-Variance
คือ การแปลง Type ของ Generic Type
ปกติ เราไม่สามารถ assign IEnumerable<string> ไปที่ IEnumerable<object> ได้
แต่ C# 4.0 ทำได้

มีข้อกำหนดนิดหน่อยว่า คุณไม่สามารถทำ Co-Variance และ Contra-Variance พร้อมกันได้
คุณสามารถทำ Co-Variance ในกรณีที่ Type นั้นเป็น output ของ Method เท่านั้น เช่น
IEnumerable<T> มี Method เดียวคือ IEnumerator<T> GetEnumerator()
จะเห็นว่า T อยู่ในส่วนของ output ดังนั้นเราจึงทำ Co-Variance ได้
IEnumerable<string> เป็น IEnumerable<object> ได้

ส่วน Contra-Variance จะทำได้ในกรณี Type นั้นเป็น input ของ Method เท่านั้น เช่น
IComparer<T> มี Method เดียวคือ int Compare(T a, T b)
จะเห็นว่า T อยู่ในส่วนของ input ดังนั้นเราจึงทำ Contra-Variance ได้
IComparer<object> เป็น IComparer<string> ได้

และมีกรณีที่ไม่สามารถทำทั้ง Co- และ Contra-Variance ได้
คือ Type นั้นเป็น Value Type เช่น IEnumerable<int> ไม่สามารถเป็น IEnumerable<object> ได้
อีกแบบคือ Type นั้นเป็นทั้ง Input และ Output ของ Method เช่น
List<T> มีทั้ง T List.get_Item(int a) และ void List.set_Item(int a, T item)
จะเห็นว่า T อยู่ทั้งในส่วนของ Input และ Output จึงไม่สามารถทำ Co- และ Contra-Variance ได้

และจะมีอะไรใน C# 5.0?
ใน Video จะมีปิดท้าย โชว์ Compiler as a Service ของ C# ถัดไปอีก
เหมือนกับ Eval ใน JavaScript ที่สามารถเขียน Code ด้วย string ได้ (ซึ่งมีเป็นชาติแล้ว)
ใน Video โชว์การทำ C# Shell ประมาณว่า เขียน Loop เขียน Function สร้าง Form จาก Shell ได้เลย
Logged

( เคยนั่งเล่นคอมเบลอ จนเอา Cursor Mouse ไปไล่แมลงวันที่แกะบน Monitor หรือปล่าว ?)

Miolynet
Moderator
เกรียนในตำนาน
*****
Offline Offline

Gender: Male
Posts: 645

( หม่าวๆ ~ แหม่วๆ )


View Profile
« Reply #1 on: July 27, 2009, 08:27:26 PM »

Introduction
The Beta for Visual Studio 2010 is upon us and included is the CTP of C# 4.0. While C# 4.0 does not represent a radical departure from the previous version, there are some key features that should be understood thoroughly in order to take advantage of their true potential.
Background
The white paper for C# 4.0's features does a good job of explaining the changes in the language. I thought, however, that some larger code samples and historical perspective would help people (especially new developers) in understanding why things have changed.
Feature Categories
Microsoft breaks the new features into the following four categories so I will maintain the pattern.
•   Named and Optional Parameters
•   Dynamic Support
•   Variance
•   COM Interop
Conventions
Some of the examples assume the following classes are defined:
 Collapse
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Customer : Person
{
    public int CustomerId { get; set; }
    public void Process() { ... }
}

public class SalesRep : Person
{
    public int SalesRepId { get; set; }
    public void SellStuff() { ... }
}
Named and Optional Parameters
We'll start off with one of the easier features to explain. In fact, if you have ever used Visual Basic, then you are probably already familiar with it.
Optional Parameters
Support for optional parameters allows you to give a method parameter a default value so that you do not have to specify it every time you call the method. This comes in handy when you have overloaded methods that are chained together.
The Old Way
 Collapse
public void Process( string data )
{
    Process( data, false );
}

public void Process( string data, bool ignoreWS )
{
    Process( data, ignoreWS, null );
}

public void Process( string data, bool ignoreWS, ArrayList moreData )
{
    // Actual work done here
}
The reason for overloading Process in this way is to avoid always having to include "false, null" in the third method call. Suppose 99% of the time, there will not be 'moreData' provided. It seems ridiculous to type and pass null so many times.
 Collapse
// These 3 calls are equivalent
Process( "foo", false, null );
Process( "foo", false );
Process( "foo" );
The New Way
 Collapse
public void Process( string data, bool ignoreWS = false, ArrayList moreData = null )
{
    // Actual work done here
}
// Note: data must always be provided because it does not have a default value
Now we have one method instead of three, but the three ways we called Process above are still valid and still equivalent.
 Collapse
ArrayList myArrayList = new ArrayList();
Process( "foo" ); // valid
Process( "foo", true ); // valid
Process( "foo", false, myArrayList ); // valid
Process( "foo", myArrayList ); // Invalid! See next section
Awesome, one less thing VB programmers can brag about having to themselves. I haven't mentioned it up to this point, but Microsoft has explicitly declared that VB and C# will be "co-evolving" so the number of disparate features is guaranteed to shrink over time. I would like to think this will render the VB vs. C# question moot, but I'm sure people will still find a way to argue about it. ;-)
Named Parameters
In the last example, we saw that the following call was invalid:
 Collapse
Process( "foo", myArrayList ); // Invalid!
But if the boolean ignoreWS is optional, why can't we just omit it? Well, one reason is for readability and maintainability, but primarily because it can become impossible to know what parameter you are specifying. If you had two parameters of the same type, or if one of the parameters was "object" or some other base class or interface, the compiler would not know which parameter you are sending. Imagine a method with ten optional parameters and you give it a single ArrayList. Since an ArrayList is also an object, an IList, and an IEnumerable, it is impossible to determine how to use it. Yes, the compiler could just pick the first valid option for each parameter (or a more complex system could be used), but this would become impossible for people to maintain and would cause countless programming mistakes.
Named parameters provide the solution:
 Collapse
ArrayList myArrayList = new ArrayList();
Process( "foo", true ); // valid, moreData omitted
Process( "foo", true, myArrayList ); // valid
Process( "foo", moreData: myArrayList); // valid, ignoreWS omitted
Process( "foo", moreData: myArrayList, ignoreWS: false ); // valid, but silly
As long as a parameter has a default value, it can be omitted, and you can just supply the parameters you want to via their name. Note in the second line above, the 'true' value for ignoreWS did not have to be named since it is the next logical parameter.
Dynamic Support
Ok, I'm sure we all have had to deal with code similar to the following:
 Collapse
public object GetCustomer()
{
    Customer cust = new Customer();
    ...
    return cust;
}
...
Customer cust = GetCustomer() as Customer;
if( cust != null )
{
    cust.FirstName = "foo";
}
Note the GetCustomer method returns object instead of Customer. Code like this is frustrating because you know it returns a Customer; it always has and it always will. Unfortunately the coder chose to return object and you can't change it because it modifies the public contract and could potentially break legacy software.
Another instance in which you will be dealing with an object that you know is another type is reflection.
 Collapse
Type myType = typeof( Customer );
ConstructorInfo consInfo = myType.GetContructor(new Type[]{});
object cust = consInfo.Invoke(new object[]{});
((Customer)cust).FirstName = "foo";
Because reflection can act on any type, ConstructorInfo.Invoke() must return object. Like the first example, this forces you to cast the object. While casting is easy, it is a relatively expensive operation and, after casting, you should always do a check to make sure you got what you expected. This just adds extra, tedious, code and opens the door for more programming mistakes.
Enter 'dynamic'
The dynamic keyword is new to C# 4.0 and is used to tell the compiler that a variable's type can change or that it is not known until runtime. Think of it as being able to interact with an Object without having to cast it.
 Collapse
dynamic cust = GetCustomer();
cust.FirstName = "foo"; // works as expected
cust.Process(); // works as expected
cust.MissingMethod(); // No method found!
Notice we did not need to cast nor declare cust as type Customer. Because we declared it dynamic, the runtime takes over and then searches and sets the FirstName property for us. Now, of course, when you are using a dynamic variable, you are giving up compiler type checking. This means the call cust.MissingMethod() will compile and not fail until runtime. The result of this operation is a RuntimeBinderException because MissingMethod is not defined on the Customer class.
Switching between Static and Dynamic
It should be apparent that 'switching' an object from being statically typed to dynamic is easy. After all, how hard is it to 'lose' information? Well, it turns out that going from dynamic to static is just as easy.
 Collapse
Customer cust = new Customer();
dynamic dynCust = cust; // static to dynamic, easy enough
dynCust.FirstName = "foo";
Customer newCustRef = dynCust; // Works because dynCust is a Customer
Person person = dynCust; // works because Customer inherits from Person
SalesRep rep = dynCust; // throws RuntimeBinderException exception
Note that in the example above, no matter how many different ways we reference it, we only have one Customer object (cust).
Functions
When you return something from a dynamic function call, indexer, etc., the result is always dynamic. Note that you can, of course, cast the result to a known type, but the object still starts out dynamic.
 Collapse
dynamic cust = GetCustomer();
string first = cust.FirstName; // conversion occurs
dynamic id = cust.CustomerId; // no conversion
object last = cust.LastName; //conversion occurs
There are, of course, a few missing features when it comes to dynamic types. Among them are:
•   Extension methods are not supported
•   Anonymous functions cannot be used as parameters
We will have to wait for the final version to see what other features get added or removed.
Variance
Ok, a quick quiz. Is the following legal in .NET?
 Collapse
// Example stolen from the whitepaper  ;-)
IList<string> strings = new List<string>();
IList<object> objects = strings;
I think most of us, at first, would answer 'yes' because a string is an object. But the question we should be asking ourselves is: Is a -list- of strings a -list- of objects? To take it further: Is a -strongly typed- list of strings a -strongly typed- list of objects? When phrased that way, it's easier to understand why the answer to the question is 'no'.
If the above example was legal, that means the following line would compile:
 Collapse
objects.Add(123);
Oops, we just inserted the integer value 123 into a List<string>. Remember, the list contents were never copied; we simply have two references to the same list. There is a case, however, when casting the list this should be allowed. If the list is read-only then we should be allowed to view the contents any (type legal) way we want.
Co and Contra Variance
From Wikipedia:
Within the type system of a programming language, a type conversion operator is:
•   covariant if it preserves the ordering, =, of types, which orders types from more specific to more generic;
•   contravariant if it reverses this ordering, which orders types from more generic to more specific;
•   invariant if neither of these apply.
C# is of course Covariant meaning a Customer is a Person and can always be referenced as one. There are lots of discussions on this topic and I will not cover it here. The changes in C# 4.0 only involve typed (generic) interfaces and situations like in the example above. In order to support co and contra variance, typed interfaces are going to be given 'input' and 'output' sides. So, to make the example above legal, IList must be declared in the following manner:
 Collapse
public interface IList<out T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
    ...
}
Notice the use of the out keyword. This is essentially saying the IList is readonly and it is safe to refer to a List<string> as a List<object>. Now, of course, IList is not going to be defined this way; it must support having items added to it. A better example to consider is IEnumerable which should be, and is, readonly.
 Collapse
public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}
Using out to basically mean 'read only' is straightforward, but when does using the in keyword to make something 'write only' useful? Well, it actually becomes useful in situations where a generic argument is expected and only used internally by the method. IComparer is the canonical example.
 Collapse
public interface IComparer<in T>
{
    public int Compare(T left, T right);
}
As you can see, we can't get back an item of type T. Even though the Compare method could potential act on the left and right arguments, it is kept within the method so it is a 'black hole' to clients that use the interface.
To continue the example above, this means that an IComparer<object> can be used in the place of an IComparer<string>. The C# 4.0 whitepaper sums the reason up nicely: 'If a comparer can compare any two objects, it can certainly also compare two strings.' This is counter-intuitive (or maybe contra-intuitive) because if a method expects a string, you can't give it an object.
COM Interop
This is by far the area in which I have the least experience, however I'm sure we have all had to interact with Microsoft Office at one point and make calls like this:
 Collapse
// Code simplified for this example
using Microsoft.Office.Interop;
using Microsoft.Office.Interop.Word;

object foo = "MyFile.txt";
object bar = Missing.Value;
object optional = Missing.Value;

Document doc = (Document)Application.GetDocument(ref foo, ref bar, ref optional);
doc.CheckSpelling(ref optional, ref optional, ref optional, ref optional);
There are (at least) three problems with the code above. First you have to declare all your variables as objects and pass them with the ref keyword. Second, you can't omit parameters and must also pass the Missing.Value even if you are not using the parameter. And third, behind the scenes you are using huge (in file size) interop assemblies just to make one method call.
C# 4.0 will allow you to write the code above in a much simpler form that ends up looking almost exactly like 'normal' C# code. This is accomplished by using some of the features already discussed; namely dynamic support and optional parameters.
 Collapse
// Again, simplified for example.
using Microsoft.Office.Interop.Word;

var doc = Application.GetDocument("MyFile.txt");
doc.CheckSpelling();
What will also happen behind the scenes is that the interop assembly that is generated will only include the interop code you are actually using in your application. This will cut down on application size tremendously. My apologies in advance for this weak COM example, but I hope it got the point across.
Conclusion
There are some great enchantments coming in C# 4.0. This article was intended to provide an overview of the new features and why they were created. There may be some last minute tweaks to the final product, but the features above are coming and should make a big difference in your future development.

Credit : http://www.codeproject.com/KB/cs/CSharp4_Features.aspx
Logged

( เคยนั่งเล่นคอมเบลอ จนเอา Cursor Mouse ไปไล่แมลงวันที่แกะบน Monitor หรือปล่าว ?)

Miolynet
Moderator
เกรียนในตำนาน
*****
Offline Offline

Gender: Male
Posts: 645

( หม่าวๆ ~ แหม่วๆ )


View Profile
« Reply #2 on: July 27, 2009, 08:27:52 PM »

Introduction
After watching Anders Hejlsberg’s session, The Future of C# on Channel 9, I was excited to get my hands on the upcoming features of C#. Since the inception of C#, each version bought some major changes and amendments in the language. For example, in C# 1.0, the major theme was Managed Code. Then in C# 2.0, Generics were introduced and lastly in C# 3.0 LINQ was introduced. C# 4.0 introduced the concept of Dynamic Programming in C#. Overall there are four main features that are introduced in the upcoming C# 4.0:
1.   Dynamic Typed Objects
2.   Optional and Named Parameters
3.   Improved COM Interoperability
4.   Co- and Contra-Variance
Today, we will see the first two features, i.e. Dynamic Typed Object, Optional Parameters and Named Argument. A document related to New Features in C# is available at MSDN that explains all of the above features in a little detail. Plus if you are interested in getting an early look at Visual Studio 2010 CTP, you can follow my post on Visual Studio 2010 CTP. Please note that this article is written using CTP version. The final product and its features may change upon final release.
Dynamic Programming
C# 4.0 supports Dynamic Programming by introducing new Dynamic Typed Objects. The type of these objects is resolved at run-time instead of at compile-time. A new keyword dynamic is introduced to declare dynamic typed object. The keyword tells the compiler that everything to do with the object, declared as dynamic, should be done dynamically at the run-time using Dynamic Language Runtime(DLR). Remember dynamic keyword is different from var keyword. When we declare an object as var, it is resolved at compile-time whereas in case of dynamic, the object type is dynamic and it's resolved at run-time. Let’s do some coding to see the advantage of Dynamic Typed Objects. Smiley
A year ago, I wrote a code of setting the property of an object using Reflection:
 Collapse
   1:  Assembly asmLib= Assembly.LoadFile(@"C:\temp\DemoClass\bin\Debug\DemoClass.dll");
   2:  Type demoClassType = asmLib.GetType("DemoClass.DemoClassLib");
   3:  object demoClassobj= Activator.CreateInstance(demoClassType);
   4:  PropertyInfo pInfo= demoClassType.GetProperty("Name");
   5:  pInfo.SetValue(demoClassobj, "Adil", null);
Notice lines 3-5 create instance of ‘demoClassType’ and set property ‘Name’ to ‘Adil’. Now with C# 4.0, line # 3-5 can be written as simple as:
 Collapse
dynamic dynamicDemoClassObj = Activator.CreateInstance(demoClassType);
dynamicDemoClassObj.Name = "Adil";
Simple, isn't it? Let’s see a slide from Anders Hejlsberg’s session at PDC 2008:
 
From the above slide, you can call method(s) such as x.ToString(), y.ToLower(), z.Add(1), etc. and it will work smoothly. Smiley
This feature is great and provides much flexibility for developers. Of course there are pros and cons of dynamic programming as well but where C# is going is something like having features of both static languages and dynamic languages.
Optional Parameters
The second feature is Optional Parameters. Let’s say I have a class Employee and I provide few overloads of the constructor to enable making certain parameters as optional as follows:
 Collapse
 public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Qualification { get; set; }
        public string MiddleName { get; set; }

        public Employee(string firstName, string lastName)
        {
            FirstName= firstName;
            LastName= lastName;
            Qualification= "N/A";
            MiddleName= string.Empty;
        }
        public Employee(string firstName, string lastName, string qualification)
        {
            FirstName= firstName;
            LastName= lastName;
            Qualification= qualification;
            MiddleName= string.Empty;

        }
        public Employee(string firstName, string lastName, string qualification,
            string middleName)
        {
            FirstName= firstName;
            LastName= lastName;
            Qualification= qualification;
            MiddleName= middleName
        }
    }
With C# 4.0, you need to create just one constructor for that as follows:
 Collapse
public Employee(string firstName, string lastName,
            string qualification = "N/A", string middleName = "")
{
    FirstName= firstName;
    LastName= lastName;
    Qualification= qualification;
    MiddleName = middleName;
}
As simple as that Smiley and you can easily call that as follows:
 Collapse
Employee(“Adil”,”Mughal”);
This feature was available in some other languages but was for some reason not provided in C# yet, but now it’s available. This feature has a good impact in COM interop which allows developers to skip missing parameters which we will hopefully see in later post(s). Finally, the compiler will always fill the optional parameters by their default given values, if you do not provide them. For instance, in our current case, it will be:
 Collapse
Employee emp= newoyee("Adil", "Mughal");
Simple but useful feature!
Named Argument
So, we discussed an example of Employee class in which we passed some optional parameters in the constructor:
 Collapse
public Employee(string firstName, string lastName,
   string qualification = "N/A", string middleName = "")
And I can simply call that as shown below:
 Collapse
Employee emp= new Employee("Adil", "Mughal");
A question can be raised "Is there any way that we can skip qualification, i.e. third parameter and give the last parameter of middleName?"
The answer of this question is "Yes absolutely, we can and that feature is called Named Argument in C# 4.0." We can simply do this like:
 Collapse
Employee emp = new Employee("Adil", "Mughal", middleName: "Ahmed");
Good enough to answer the query. Smiley. Now let’s make some changes with the Employee constructor and make lastName optional as well:
 Collapse
public Employee(string firstName, string lastName = "",
      string qualification = "N/A", string middleName = "")
Now I can instantiate object of Employee in quite simple and flexible ways:
 Collapse
Employee("Adil", qualification:"BS");
Employee("ABC", lastName: "EFG", qualification: "BS");
Employee("XYZ", middleName: "MNO");
Conclusion
These upcoming features are really cool as they will enable C# developers to be more productive with the help of dynamic programming and optional parameters though some of the features are not new in the programming languages’ world.
Logged

( เคยนั่งเล่นคอมเบลอ จนเอา Cursor Mouse ไปไล่แมลงวันที่แกะบน Monitor หรือปล่าว ?)

ton_nam
เกรียน
**
Offline Offline

Posts: 60



View Profile
« Reply #3 on: July 31, 2009, 05:58:59 PM »

ขยันจิงๆ โปรแกรมเมอร์ สู้ๆ เข้ามาศึกษาหาความรู้
Logged
HelenJames
กาก
*
Offline Offline

Posts: 1


View Profile
« Reply #4 on: July 28, 2010, 07:04:55 AM »

The similar subject was already observed somewhere at this thread
Logged
Pages: [1]   Go Up
Print
 
Jump to: