Chuyển đổi loại chung TỪ chuỗi


234

Tôi có một lớp mà tôi muốn sử dụng để lưu trữ "thuộc tính" cho một lớp khác. Các thuộc tính này chỉ đơn giản là có một tên và một giá trị. Lý tưởng nhất, điều tôi muốn là có thể thêm các thuộc tính được gõ , sao cho "giá trị" được trả về luôn thuộc loại mà tôi muốn.

Các loại phải luôn luôn là một nguyên thủy. Lớp này phân lớp một lớp trừu tượng về cơ bản lưu trữ tên và giá trị dưới dạng chuỗi. Ý tưởng là lớp con này sẽ thêm một số loại an toàn cho lớp cơ sở (cũng như tiết kiệm cho tôi một số chuyển đổi).

Vì vậy, tôi đã tạo ra một lớp (đại khái) này:

public class TypedProperty<DataType> : Property
{
    public DataType TypedValue
    {
        get { // Having problems here! }
        set { base.Value = value.ToString();}
    }
}

Vì vậy, câu hỏi là:

Có cách nào "chung chung" để chuyển đổi từ chuỗi trở lại nguyên thủy không?

Tôi dường như không thể tìm thấy bất kỳ giao diện chung nào liên kết chuyển đổi trên bảng (thứ gì đó như ITryParsable sẽ là lý tưởng!).


Tôi muốn thấy một ví dụ về lớp học cụ thể của bạn, thậm chí chỉ là một đoạn trích. :)
Jon Limjap

bạn có thể vui lòng gửi các phần có liên quan của lớp cơ sở của bạn?
JJS

Tôi tự hỏi liệu có ai có thể nhận được câu trả lời ở đây khi làm việc trong .Net Standard 1.2: /
Dan Rayson

Câu trả lời:


374

Tôi không chắc liệu tôi có hiểu chính xác ý định của bạn không, nhưng hãy xem liệu điều này có giúp ích gì không.

public class TypedProperty<T> : Property where T : IConvertible
{
    public T TypedValue
    {
        get { return (T)Convert.ChangeType(base.Value, typeof(T)); }
        set { base.Value = value.ToString();}
    }
}

Trong vài ngày, tôi đã tự hỏi làm thế nào để khử lưu lượng một luồng thành một loại chung. Cảm ơn :)
Bẫy

3
Tôi đồng ý, mặc dù Convert.ChangeTypekhông phải là giải pháp rất phổ quát và có thể mở rộng, nhưng nó hoạt động cho hầu hết các loại cơ bản. nếu cần một cái gì đó tốt hơn, sẽ không có vấn đề gì khi bọc phương thức này thành thứ gì đó lớn hơn như Tim đề xuất hoặc sử dụng phương pháp chuyển đổi khác nhau hoàn toàn.
Lubos hasko

18
Tôi chắc chắn sẽ thêm nơi T: IConvertible
MikeT

5
Loại T không nên là IConvertible, nhưng Loại cơ sở. Giá trị nên.
chapluck

74

Phương pháp của Lubos hasko thất bại cho nullables. Phương pháp dưới đây sẽ làm việc cho nullables. Tôi đã không đến với nó, mặc dù. Tôi đã tìm thấy nó qua Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Tín dụng cho "Tuna Toksoz"

Cách sử dụng đầu tiên:

TConverter.ChangeType<T>(StringValue);  

Lớp học dưới đây.

public static class TConverter
{
    public static T ChangeType<T>(object value)
    {
        return (T)ChangeType(typeof(T), value);
    }

    public static object ChangeType(Type t, object value)
    {
        TypeConverter tc = TypeDescriptor.GetConverter(t);
        return tc.ConvertFrom(value);
    }

    public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
    {

        TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
    }
}

tôi sẽ thêm một tùy chọn chuyển đổi dự phòng cho Enums và các cấu trúc phức tạp khác, nhưng cuộc gọi tốt.
Tomer W

2
Tại sao RegisterTypeConverter? Chúng ta có cần phải đăng ký bộ chuyển đổi trước khi ra tay không? (không may là liên kết đã chết, vì vậy tôi không thể đọc được nó)
Cohen

Đối với nhiều chuyển đổi, có lẽ bạn chỉ nên tạo tc(một TypeConverter) lần duy nhất. TypeConverterlà chậm vì nó sử dụng sự phản chiếu để tìm kiếm TypeConverterAttribute. Nếu bạn khởi tạo một TypeConvertertrường riêng tư , thì bạn sẽ có thể sử dụng lại TypeConverternhiều lần.
Kevin P. Rice

Hoạt động tốt, nhưng nếu T là một object, ném một ngoại lệ. Tôi đã có thể giải quyết rằng bằng cách sử dụng `if (typeof (T) .IsPrimitive) {return TConverter.ChangeType <T> (StringValue); } other {object o = (object) StringValue; trở lại; } `thay thế cho mẫu Sử dụng TConverter.ChangeType<T>(StringValue)
Matt

14

Đối với nhiều loại (số nguyên, gấp đôi, DateTime, v.v.), có một phương thức Parse tĩnh. Bạn có thể gọi nó bằng phản chiếu:

MethodInfo m = typeof(T).GetMethod("Parse", new Type[] { typeof(string) } );

if (m != null)
{
    return m.Invoke(null, new object[] { base.Value });
}

8
TypeDescriptor.GetConverter(PropertyObject).ConvertFrom(Value)

TypeDescriptorlà lớp có phương thức GetConvertorchấp nhận một Typeđối tượng và sau đó bạn có thể gọi ConvertFromphương thức để chuyển đổi valueđối tượng được chỉ định đó.


Cá nhân tôi nghĩ rằng giao diện này tốt hơn để xử lý hội tụ thay vì phương thức Convert.ChangeType vì bạn cần triển khai giao diện IConvertible trên tất cả các lớp của mình.
Sauleil

3

Bạn có thể có thể sử dụng một cấu trúc như lớp đặc điểm . Theo cách này, bạn sẽ có một lớp trình trợ giúp được tham số hóa, biết cách chuyển đổi một chuỗi thành một giá trị của kiểu riêng của nó. Sau đó, getter của bạn có thể trông như thế này:

get { return StringConverter<DataType>.FromString(base.Value); }

Bây giờ, tôi phải chỉ ra rằng trải nghiệm của tôi với các loại được tham số hóa chỉ giới hạn ở C ++ và các mẫu của nó, nhưng tôi tưởng tượng có một số cách để thực hiện cùng một thứ bằng cách sử dụng chung chung C #.


Các phiên bản chung không tồn tại trong C #.
Shimmy Weitzhandler

3

Kiểm tra tĩnh Nullable.GetUnderlyingType. - Nếu loại cơ bản là null, thì tham số mẫu không phải là Nullablevà chúng ta có thể sử dụng loại đó trực tiếp - Nếu loại cơ bản không phải là null, thì hãy sử dụng loại cơ bản trong chuyển đổi.

Dường như làm việc cho tôi:

public object Get( string _toparse, Type _t )
{
    // Test for Nullable<T> and return the base type instead:
    Type undertype = Nullable.GetUnderlyingType(_t);
    Type basetype = undertype == null ? _t : undertype;
    return Convert.ChangeType(_toparse, basetype);
}

public T Get<T>(string _key)
{
    return (T)Get(_key, typeof(T));
}

public void test()
{
    int x = Get<int>("14");
    int? nx = Get<Nullable<int>>("14");
}

1

Với cảm hứng từ câu trả lời của Bob , các tiện ích mở rộng này cũng hỗ trợ chuyển đổi giá trị null và tất cả chuyển đổi nguyên thủy trở lại và thứ tư.

public static class ConversionExtensions
{
        public static object Convert(this object value, Type t)
        {
            Type underlyingType = Nullable.GetUnderlyingType(t);

            if (underlyingType != null && value == null)
            {
                return null;
            }
            Type basetype = underlyingType == null ? t : underlyingType;
            return System.Convert.ChangeType(value, basetype);
        }

        public static T Convert<T>(this object value)
        {
            return (T)value.Convert(typeof(T));
        }
}

Ví dụ

            string stringValue = null;
            int? intResult = stringValue.Convert<int?>();

            int? intValue = null;
            var strResult = intValue.Convert<string>();

0
public class TypedProperty<T> : Property
{
    public T TypedValue
    {
        get { return (T)(object)base.Value; }
        set { base.Value = value.ToString();}
    }
}

Tôi sử dụng chuyển đổi thông qua một đối tượng. Nó là một chút đơn giản hơn.


cảm ơn tôi phải chuyển đổi T trong giao diện và đối tượng T chuyển đổi đơn giản hoạt động chính xác, dễ dàng và nhanh chóng
LXG

5
(int) (đối tượng) "54"; là một KHẢ NĂNG!, đây không phải là VB!
Tomer W

0

Tôi đã sử dụng lobos trả lời và nó hoạt động. Nhưng tôi gặp vấn đề với việc chuyển đổi gấp đôi vì cài đặt văn hóa. Vì vậy, tôi đã thêm

return (T)Convert.ChangeType(base.Value, typeof(T), CultureInfo.InvariantCulture);

0

Một biến thể khác. Xử lý Nullables, cũng như các tình huống trong đó chuỗi là null và T không thể rỗng.

public class TypedProperty<T> : Property where T : IConvertible
{
    public T TypedValue
    {
        get
        {
            if (base.Value == null) return default(T);
            var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
            return (T)Convert.ChangeType(base.Value, type);
        }
        set { base.Value = value.ToString(); }
    }
}

0

Bạn có thể làm điều đó trong một dòng như dưới đây:

YourClass obj = (YourClass)Convert.ChangeType(YourValue, typeof(YourClass));

Chúc mừng mã hóa;)


Khi bạn chia sẻ mã dưới dạng câu trả lời, hãy cố gắng giải thích nó.
Yunus Temurlenk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.