Thứ bảy, ngày 3 tháng 12 năm 2016

.NET – Tạo instance và chuyển đổi kiểu dữ liệu bất kì

Ngày đăng: 10/4/2012, 8:32:59AM | Lượt xem: 5,487
Hot!

Trong bài viết này, tôi sẽ giới thiệu cách giải quyết hai vấn đề bạn có thể gặp phải khi làm việc với .NET: - Tạo instance của một kiểu dữ liệu bất kì với . - Chuyển đổi một đối tượng sang một kiểu dữ liệu bất kì.

dot_net_splashTrong bài viết này, tôi sẽ giới thiệu cách giải quyết hai vấn đề bạn có thể gặp phải khi làm việc với .NET:
- Tạo instance của một kiểu dữ liệu bất kì với .
- Chuyển đổi một đối tượng sang một kiểu dữ liệu bất kì.

Tạo instance của một kiểu dữ liệu bất kì

Việc tạo instance của một kiểu dữ liệu chỉ cần sử dụng phương thức Activator.CreateInstance(). Tuy nhiên đối với các kiểu dữ liệu không chứa parameterless constructor (phương thức khởi tạo không có tham số) thì phương thức này sẽ ném ra ngoại lệ MissingMethodException “No parameterless constructor defined for this object”.

Để giải quyết, tôi sẽ thay thế phương thứcc này bằng phương thức FormatterServices.GetUninitializedObject(). Tuy nhiên, phương thức vẫn không thể tạo được instance của kiểu string, vì vậy thay vì dùng reflection, tôi phải giải quyết bằng cách sau:

private static T CreateInstance()
{
    var type = typeof(T);
    if (type == typeof(string))
    {
        return (T)(object)String.Empty;
    }
    else
    {
        return (T)FormatterServices.GetUninitializedObject(type);
    }
}

Chuyển đổi đối tượng sang kiểu dữ liệu bất kì

Với các kiểu dữ liệu nguyên thủy (primitive type), bạn có thể dùng phương thức Convert.ChangeType() để chuyển đổi. Với kiểu dữ liệu phức tạp, cách linh hoạt nhất là sử dụng reflection để lặp qua các property của đối tượng nguồn và gán cho property tương ứng của đối tượng đích.

public static TDest ChangeType(object source)
{
    var destObj = CreateInstance();

    var sourceType = source.GetType();
    var destType = typeof(TDest);

    if (sourceType.IsValueType || destType.IsValueType)
        return (TDest)Convert.ChangeType(source, destType);

    var properties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

    foreach (var prop1 in properties)
    {

        var prop2 = destType.GetProperty(prop1.Name);

		// destType does not has a property named prop1.Name
        if (prop2 == null)
            continue;

        var value = prop1.GetValue(source, null);

		// prop1 and prop2 are not same type
        if (prop1.PropertyType != prop2.PropertyType)
            continue;

        prop2.SetValue(destObj, value, null);
    }
    return destObj;
}

Bổ sung theo lời khuyên của anh Lê Hoàng Dũng(7 March, 2012):

Viết dưới dạng extension method với tên ToType():

static class Y2Extensions
{
    public static T CreateInstance()
    {
        var type = typeof(T);
        if (type == typeof(string))
        {
            return (T)(object)String.Empty;
        }
        else
        {
            return (T)FormatterServices.GetUninitializedObject(type);
        }
    }

    public static TDest ToType(this object source)
    {
        var destObj = CreateInstance();

        var sourceType = source.GetType();
        var destType = typeof(TDest);

        if (sourceType.IsValueType || destType.IsValueType)
            return (TDest)Convert.ChangeType(source, destType);

        var properties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

        foreach (var prop1 in properties)
        {

            var prop2 = destType.GetProperty(prop1.Name);

            // destType does not has a property named prop1.Name
            if (prop2 == null)
                continue;

            var value = prop1.GetValue(source, null);

            // prop1 and prop2 are not same type
            if (prop1.PropertyType != prop2.PropertyType)
                continue;

            prop2.SetValue(destObj, value, null);
        }
        return destObj;
    }

}

Kiểm tra kết quả

Để kiểm tra, tôi tạo hai class Foo và Bar sau:

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
}

class Bar
{
    public int Id { get; set; }
    public string Name { get; set; }

    public string CreateDate { get; set; }

	// This class doest not has a parameterless constructor
	public Bar(int id) { }

    public override string ToString()
    {
        return String.Format("Bar: {0} - {1} - {2}",
            Id, Name, String.IsNullOrEmpty(CreateDate)?"N/A":CreateDate);
    }
}

Và phương thức Main():

static void Main(string[] args)
{
    Console.WriteLine("1111".ToType()* 2);  // 2222

    var foo = new Foo { Id = 1, Name = "Foo1", CreateDate = DateTime.Today };

    var bar = foo.ToType();

    Console.WriteLine(bar); // Bar: 1 - Foo1 - N/A

    Console.Read();
}

Output:

2222
Bar: 1 - Foo1 - N/A

YinYang’s Programming Blog

 Chia sẻ qua: 
Hot!
Ý kiến bạn đọc

These items will be permanently deleted and cannot be recovered. Are you sure?

Gallery

image

Maecenas viverra rutrum pulvinar

Maecenas viverra rutrum pulvinar! Aenean vehicula nulla sit amet metus aliquam et malesuada risus aliquet. Vestibulum rhoncus, dolor sit amet venenatis porta, metus purus sagittis nisl, sodales volutpat elit lorem…

Read more

Text Links

Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
Copyright © 2011 - 2012 vietshare.vn by phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.