Lập trình C#

Các cách chuyển đổi kiểu dữ liệu trong C#

Các cách chuyển đổi kiểu dữ liệu trong C#
Được viết bởi Minh Hoàng

Series lập trình C#, ngôn ngữ lập trình hiện đại và mạnh mẽ.

Chuyển đổi kiểu dữ liệu là gì ?

Chuyển đổi kiểu dữ liệu hay còn gọi là ép kiểu(casting) là biến đổi dữ liệu thuộc kiểu dữ liệu này thành kiểu dữ liệu khác.

Tại sao cần chuyển đổi kiểu dữ liệu ?

  • Để chuyển dữ liệu sang một kiểu dữ liệu mong muốn phục vụ cho một hay nhiều xử lý nhất định.
  • Để chuyển dữ liệu về định dạng mong muốn (ví dụ như muốn chuyển định dạng của một chuỗi ngày tháng Việt Nam(17/07/2017) thành định dạng theo kiểu Nhật Bản(2017/07/17))

Trong C# có mấy loại chuyển đổi kiểu dữ liệu ?

Có 4 cách để chuyển đổi:

  1. Chuyển đổi kiểu ngầm định (Implicit)
  2. Chuyển đổi kiểu tường minh (Explicit)
  3. Sử dụng phương thức, lớp hỗ trợ sẵn
    • Dùng phương thức Parse(), TryParse()
    • Dùng lớp hỗ trợ sẵn Convert
  4. Do lập trình viên tự định nghĩa cách chuyển đổi

Nội dung chi tiết:

1. Chuyển đổi kiểu ngầm định (Implicit)
1. Chuyển đổi kiểu ngầm định (Implicit)

– Việc chuyển đổi này được thực hiện bởi C# theo một phương thức an toàn kiểu (type-safe), không cần lập trình viên can thiệp.

– Được thực hiện khi muốn chuyển đổi kiểu dữ liệu:

  • Có miền giá trị nhỏ sang kiểu dữ liệu có miền giá trị lớn hơn (Để xác định được miền giá trị của một kiểu dữ liệu cụ thể, xem bài Kiểu dữ liệu)
  • Từ lớp dẫn xuất(lớp con) thành lớp cơ sở(lớp cha) (Khái niệm lớp dẫn xuất, lớp cơ sở được trình bày trong bài Tính kế thừa).
[code language=”csharp” highlight=”3,6,10″] // 1. Ép kiểu từ kiểu có miền giá trị nhỏ qua kiểu có miền giá trị lớn
byte b = 7;
int i = b; /* Kiểu int có miền giá trị lớn hơn kiểu byte */

float flt = 13.3f;
double dbl = flt; /* Kiểu double có miền giá trị lớn hơn kiểu float */

// 2. Ép kiểu từ lớp dẫn xuất(string) qua lớp cơ sở(object)
string s = "Hello World";
object o = s;
[/code]

2. Chuyển đổi kiểu tường minh (Explicit)
2. Chuyển đổi kiểu tường minh (Explicit)

– Việc chuyển đổi này được thực hiện một cách rõ ràng bởi lập trình viên bằng việc sử dụng một toán tử cast là 2 dấu đóng mở ngoặc tròn () bao ngoài kiểu dữ liệu muốn cast.

– Một số đặc điểm của chuyển đổi kiểu tường minh:

  • Hỗ trợ trong việc boxing và unboxing đối tượng. (Xem bài Kiểu dữ liệu)
  • Chỉ khi chúng ta biết rõ biến đó thuộc kiểu dữ liệu nào mới thực hiện chuyển đổi. Nếu không có thể lỗi khi chạy chương trình.
  • Thường được dùng để chuyển đổi giữa các kiểu dữ liệu có tính chất tương tự nhau(Thường dùng với số). Đối với trường hợp là số thì:
    • Chúng ta có thực hiện ép kiểu dữ liệu lớn hơn về kiểu dữ liệu nhỏ hơn mà không báo lỗi.
    • Nếu dữ liệu cần ép kiểu vượt quá miền giá trị của kiểu dữ liệu muốn ép kiểu về thì chương trình sẽ tự cắt bit(từ trái qua) cho phù hợp với khả năng chứa kiểu dữ liệu đó. Vì vậy mà cũng có trường hợp làm thay đổi giá trị của biến kiểu ban đầu sau khi ép kiểu.
[code language=”csharp” highlight=”3,15,23″] // Trường hợp giá trị sau khi cast bị thay đổi do Kiểu cần ép vượt quá miền giá trị của kiểu dữ liệu muốn ép
int num1 = 300;
byte b = (byte)num1;
/* Vì kiểu byte có giới hạn đến giá trị 255, nên không thể chứa số 300 được.
* Kiểu byte có kích thước là 1 byte tương đương 8 bits. Do đó chương trình sẽ cắt mã nhị phân tính từ trái qua của số 300 về còn 8 bits.
* Mã nhị phân của số 300 là 100101100 cắt từ trái qua 1 bit ta được 00101100 (đủ 8 bit) tương đương với số 44.
* Nên cuối cùng biến b sẽ có giá trị là 44.
* http://www.binaryhexconverter.com/binary-to-decimal-converter
*/

Console.WriteLine("num1 = " + num1); // 300
Console.WriteLine("b = " + b); // 44

double dbl = 29.89;
int num2 = (int)dbl;

Console.WriteLine("dbl = " + dbl); // 29.89
Console.WriteLine("num2 = " + num2); // 29

// Ép kiểu từ lớp cơ sở(object) qua lớp dẫn xuất(string)
string str1 = "Hello World";
object obj = str1;
string str2 = (string)obj;

Console.WriteLine("str2 = " + str2); // Hello World
[/code]

3. Sử dụng phương thức, lớp hỗ trợ sẵn
3. Sử dụng phương thức, lớp hỗ trợ sẵn
#1. Sử dụng phương thức Parse()

– Phương thức Parse là phương thức được sử dụng khá phổ biến khi chúng ta muốn chuyển đổi một chuỗi sang một kiểu dữ liệu tương ứng.
Mỗi kiểu dữ liệu cơ bản trong C# đều có phương thức Parse để chuyển đổi sang kiểu dữ liệu đó. Chúng ta có Boolean.Parse dùng để chuyển về kiểu Boolean, Int32.Parse dùng để chuyển về kiểu Int32, Double.Parse dùng để chuyển chuỗi về kiểu Double,…

– Cách sử dụng:

[code language=”csharp”] string stringValue = "123";
int a = int.Parse( stringValue ); // a sẽ mang giá trị 123

float b = float.Parse( "20.7" ); // b sẽ mang giá trị 20.7
bool c = bool.Parse( "true" ); // c sẽ mang giá trị True
[/code]

– Nếu như chuỗi chúng ta truyền vào là rỗng, không đúng định dạng hoặc vượt quá giá trị cho phép thì chúng ta sẽ nhận được các Exception tương ứng.

[code language=”csharp”] int a = Int32.Parse( "Hello" ); // Sai định dạng, bị lỗi: FormatException

byte b = Byte.Parse( "256" ); // Vượt quá giới hạn miền giá trị, bị lỗi: OverflowException

bool c = Boolean.Parse( null ); // Tham số là null, bị lỗi: ArgumentNullException
[/code]

#2. Sử dụng phương thức TryParse()

– Giống như Parse, TryParse cũng là phương thức được tích hợp sẵn trong các lớp kiểu dữ liệu cơ bản của C#. Tuy nhiên, cú pháp của TryParse có phần khác với Parse:

  • Tham số thứ nhất của TryParse là chuỗi/giá trị cần chuyển đổi.
  • Tham số thứ hai là biến sẽ chứa giá trị sau khi được chuyển đổi đi kèm với từ khóa out, để thông báo rằng biến thứ hai sẽ truyền theo kiểu tham chiếu (Xem bài Cách truyền tham trị, tham chiếu trong C#)

– Cách sử dụng:

[code language=”csharp”] // Bước 1: Khai báo biến sẽ nhận kết quả sau khi chuyển đổi
int a;
// Bước 2: Sử dụng phương thức TryParse để chuyển đổi
int.TryParse("123", out a); /* Hoặc: Int32.TryParse("123", out a);  */
Console.WriteLine("a = {0}", a); /* Ouput: a = 123 */

bool b;
bool.TryParse("true", out b); /* Hoặc: Boolean.TryParse("true", out b);  */
Console.WriteLine("b = {0}", b); /* Ouput: b = True */

// Chuyển đổi kiểu DateTime
DateTime result = DateTime.Now;

string day1 = "2017年06月17日";
string day2 = "2017/06/17";

DateTime.TryParse(day1, out result);
Console.WriteLine(result); /* Output: 2017/06/17 0:00:00   */

DateTime.TryParse(day2, out result);
Console.WriteLine(result); /* Output: 2017/06/17 0:00:00   */
[/code]

– Điểm khác biệt thứ hai của TryParse so với Parse là phương thức TryParse khi chuyển đổi kiểu bị lỗi sẽ không ném ra các ngoại lệ như Parse mà sẽ trả về giá trị mặc định của kiểu dữ liệu chuyển đổi (int trả về 0, bool trả về False,… )

[code language=”csharp”] double a;
double.TryParse("Hello", out a);
Console.WriteLine("a = {0}", a); /* Ouput: a = 0  */

bool b;
Boolean.TryParse("Welcome", out b);
Console.WriteLine("b = {0}", b); /* Ouput: a = False */
[/code]

– Như vậy có thể thấy rằng sử dụng phương TryParse sẽ an toàn hơn phương thức Parse trong trường hợp chưa biết chắc chắn về giá trị muốn chuyển đổi.

#3. Sử dụng lớp hỗ trợ sẵn Convert

– Lớp Convert là một lớp tiện ích trong C# cung cấp cho chúng ta rất nhiều phương thức tĩnh khác nhau để chuyển đổi từ một kiểu dữ liệu này sang kiểu dữ liệu khác.

– Một số phương thức chuyển kiểu hay dùng của lớp Convert:

Tên phương thức Ý nghĩa
ToInt32 Chuyển đổi một kiểu thành kiểu int
ToDouble Chuyển đổi một kiểu thành kiểu double
ToByte Chuyển đổi một kiểu thành một byte (nếu có thể)
ToDateTime Chuyển đổi một kiểu thành các cấu trúc date-time
ToBoolean Chuyển đổi một kiểu thành một bool (true, false) nếu có thể
ToString Chuyển đổi một kiểu thành kiểu string
ToChar Chuyển đổi một kiểu thành một char (nếu có thể)

– Các đặc điểm của các phương thức trong lớp Convert:

  • Tham số truyền vào của các phương thức không nhất thiết là chuỗi, mà có thể ở nhiều kiểu dữ liệu khác nhau (int, bool, double…)
  • Tham số truyền vào là không đúng định dạng hoặc vượt quá giá trị cho phép thì chúng ta sẽ nhận được các Exception tương ứng.
  • Nếu tham số truyền vào là null thì các phương thức sẽ trả về giá trị mặc định của kiểu dữ liệu

– Cách sử dụng:

[code language=”csharp”] int a = Convert.ToInt32( "123" );
Console.WriteLine(a); // a = 123

double b = Convert.ToInt32( 789 );
Console.WriteLine(b); // b = 789

bool c = Convert.ToBoolean( 123 );
Console.WriteLine(c); // c = True

bool d = Convert.ToBoolean(null); // Tham số truyền vào là null -> sẽ output giá trị mặc định của kiểu dữ liệu
Console.WriteLine(d); // d = False
[/code]

4. Do lập trình viên tự định nghĩa cách chuyển đổi
4. Do lập trình viên tự định nghĩa cách chuyển đổi

– Khi chúng ta tạo ra một kiểu dữ liệu mới, tùy vào nhu cầu sử dụng mà chúng ta không cần hoặc sẽ định nghĩa cách chuyển đổi kiểu dữ liệu mới đó sang 1 trong các kiểu cơ bản và ngược lại.

– Việc thực hiện sẽ được trình bày chi tiết trong bài Cách chuyển đổi qua lại giữa kiểu dữ liệu tự định nghĩa và Kiểu string trong C#

Tổng hợp một số cách chuyển đổi kiểu int sang kiểu string

int i = 99;

string s1 = i.ToString();
string s2 = Convert.ToString(i);
string s3 = string.Format("{0}", i);
string s4 = $"{i}";
string s5 = "" + i;
string s6 = string.Empty + i;
string s7 = new StringBuilder().Append(i).ToString();

Kết luận:

C# cung cấp nhiều giải pháp để chúng ta có thể chuyển đổi từ kiểu dữ liệu này sang kiểu dữ liệu khác. Việc sử dụng phương pháp nào là tùy vào đặc điểm của chương trình cũng như thói quen của người sử dụng. Nếu như biết cách sử dụng linh hoạt giữa các phương pháp thì chúng ta có thể viết được một chương trình dễ đọc, dễ hiểu và dễ quản lý.

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi!

Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp bạn đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[...]

10 bình luận

  • Dạ em chào anh. Hiện em đang có một câu so sánh nhưng nó khác nhau kiểu dữ liệu. Làm thế nào để có thể ép kiểu MimeEntity về kiểu string được ạ.

    • Em so sánh 2 giá trị thuộc kiểu dữ liệu MimeEntity hay sao?
      Nếu đúng như vậy thì em đang thực hiện so sánh 2 object, do đó cần thực hiện override các method Object.Equals và Object.GetHashCode.

      • Dạ em có hàm AddWord được viết ntn:
        using AngleSharp.Html.Dom;
        using AngleSharp.Html.Parser;
        using System.Text.RegularExpressions;
        using MimeKit;
        using System.Linq;
        using System.IO;
        using System.Text;
        
        namespace MDFramWork
        {
         public class Body
         {
              public static MimeMessage AddWork(MimeMessage message, string   addWord, AddWordPosition addWordPosition)
             {
                  if (message.Body is TextPart)
                  {
                     TextPart targetText = message.Body as TextPart;
                     targetText.Text = AddWordToHTML(targetText.Text,               addWord,addWordPosition);
                     message.Body = targetText;
                  }
                  return message;
             }
             private static string AddWordToHTML(string targetText, string  addWord, AddWordPosition addWordPosition)
             {
                  addWord = addWord.Replace("\r\n", "<br>").Replace("\r", "  <br>").Replace("\n", "<br>");
                  if (addWordPosition == AddWordPosition.HEAD)
                  {
                      return Regex.IsMatch(targetText, "(<x?body[^>]*>)") ?
                      Regex.Replace(targetText, "(<x?body[^>]*>)", $"$1\r\n{addWord}   <br>", RegexOptions.None, new TimeSpan(0, 0,30))
                  : $"{addWord}<br>{targetText}";
                 }
                 else
                 {
                    return Regex.IsMatch(targetText, "(</x?body>)") ?
                    Regex.Replace(targetText, "(</x?body>)", $"<br>{addWord}\r\n$1", RegexOptions.None, new TimeSpan(0, 0, 30))
                    : $"{targetText}<br>{addWord}";
                }
           }
         }
        }
        
        Sau đó em viết UniTest cho hàm AddWord ntn ạ:
        using Microsoft.VisualStudio.TestTools.UnitTesting;
        using MimeKit;
        using MDFramWork;
        
        namespace TestMDFramWork
        {
        
        [TestClass]
         public class UnitTest1
         {
        
                [DataTestMethod]
                [DynamicData(nameof(Provider.AddBody), typeof(Provider),  DynamicDataSourceType.Method)]
        
               public void AddBodyTest(string mailPath, string addWord,   AddWordPosition addWordPosition, string expectedBody)
               {
                   MimeMessage message = MimeMessage.Load(mailPath);
                   message = Body.AddWork(message, addWord, addWordPosition);
                   Assert.AreEqual(expectedBody, message.Body);
              }
         }
        }
        
        hiện tại expectedBody đang ở kiểu string, còn Body đang ở kiểu MimeEntity giờ làm sao em chuyển Body về string đc ạ
        
        • Còn đây là class dữ liệu em truyền vào:
          using System;
          using System.Collections.Generic;
          using System.IO;
          using System.Text;

          namespace MDFramWork
          {
          public class Provider
          {
          public static IEnumerable<object[]> AddBody()
          {
          yield return new object[]
          {
          Path.Combine(“TestData”, “NotAttached”, “SinglePart”, “02_only_text_html.eml”),
          “[差し込み文言]”,
          AddWordPosition.TAIL,
          “<html>\r\n <head>\r\n\r\n<meta http-equiv=\”content-type\” content=\”text/html; charset=UTF-8\”>\r\n </head>\r\n <body text=\”#000000\” bgcolor=\”#FFFFFF\”>\r\n <p><font color=\”#ff0000\”>text_html</font>のみ<br>\r\n </p>\r\n <br>—–<br>差し込み文言<br>—–\r\n</body>\r\n</html>”
          };
          }
          }
          }

      • Em đang so sánh 2 giá trị nhưng Body thì nó đang thuộc kiểu MimeEntity, còn expectedBody thì đang ở kiểu string. Em muốn chuyển về kiểu string để cùng kiểu với expectedBody. Code em có để ở dưới anh xem qua giúp em với ạ.

Translate »