Konversi tipe umum DARI string

234

Saya memiliki kelas yang ingin saya gunakan untuk menyimpan "properti" untuk kelas lain. Properti ini hanya memiliki nama dan nilai. Idealnya, yang saya inginkan adalah dapat menambahkan properti yang diketik , sehingga "nilai" yang dikembalikan selalu dari tipe yang saya inginkan.

Jenisnya harus selalu primitif. Kelas ini subkelas kelas abstrak yang pada dasarnya menyimpan nama dan nilai sebagai string. Idenya adalah bahwa subclass ini akan menambahkan beberapa jenis-keamanan ke kelas dasar (serta menyelamatkan saya pada beberapa konversi).

Jadi, saya telah membuat kelas yang kira-kira:

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

Jadi pertanyaannya adalah:

Apakah ada cara "generik" untuk mengkonversi dari string kembali ke primitif?

Sepertinya saya tidak dapat menemukan antarmuka umum yang menautkan konversi di seluruh papan (sesuatu seperti ITryParsable pasti ideal!).

Rob Cooper
sumber
Saya akan tertarik melihat contoh kelas konkret Anda, bahkan hanya cuplikan. :)
Jon Limjap
dapatkah Anda memposting bagian yang relevan dari kelas dasar Anda?
JJS
Saya ingin tahu apakah ada yang bisa mendapatkan jawaban di sini dengan bekerja di. Net Standard 1.2: /
Dan Rayson

Jawaban:

374

Saya tidak yakin apakah saya memahami niat Anda dengan benar, tetapi mari kita lihat apakah ini membantu.

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();}
    }
}
lubos hasko
sumber
Saya telah bertanya-tanya selama beberapa hari bagaimana deserialize aliran menjadi tipe generik. Terima kasih :)
Trap
3
Saya setuju, meskipun Convert.ChangeTypeini bukan solusi yang sangat universal dan dapat diperluas, ini bekerja untuk sebagian besar tipe dasar. jika sesuatu yang lebih baik diperlukan, tidak ada masalah untuk membungkus metode ini menjadi sesuatu yang lebih besar seperti yang disarankan Tim atau menggunakan metode konversi yang berbeda sekaligus.
lubos hasko
18
Saya pasti akan menambahkan di mana T: IConvertible
MikeT
5
Tipe T tidak boleh IConvertible, tetapi Type of base.Value seharusnya.
chapluck
74

Metode lubos hasko gagal untuk nullables. Metode di bawah ini akan berfungsi untuk nullables. Tapi aku tidak memunculkannya. Saya menemukannya melalui Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Kredit untuk "Tuna Toksoz"

Penggunaan pertama:

TConverter.ChangeType<T>(StringValue);  

Kelasnya di bawah.

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)));
    }
}
Tim Coker
sumber
saya akan menambahkan opsi konversi Fallback untuk Enums dan struktur Kompleks Lainnya, tetapi panggilan yang baik.
Tomer W
2
Mengapa RegisterTypeConverter? Apakah kita perlu mendaftarkan konverter sebelumnya? (sayangnya tautannya sudah mati, jadi saya tidak bisa membacanya)
Cohen
Untuk beberapa konversi, Anda mungkin harus membuat tc(hanya TypeConverter) satu kali saja. TypeConverterlambat karena menggunakan refleksi untuk mencari TypeConverterAttribute. Jika Anda menginisialisasi TypeConverterbidang pribadi tunggal , maka Anda harus dapat menggunakan kembali TypeConverterberkali-kali.
Kevin P. Rice
Bekerja dengan baik, tetapi jika T adalah object, melempar pengecualian. Saya bisa mengatasinya dengan menggunakan `if (typeof (T) .IsPrimitive) {return TConverter.ChangeType <T> (StringValue); } else {object o = (object) StringValue; kembali ke; } `sebagai pengganti untuk sampel Penggunaan TConverter.ChangeType<T>(StringValue)
Matt
14

Untuk banyak jenis (integer, dobel, DateTime dll), ada metode Parse statis. Anda dapat memintanya menggunakan refleksi:

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

if (m != null)
{
    return m.Invoke(null, new object[] { base.Value });
}
dbkk
sumber
8
TypeDescriptor.GetConverter(PropertyObject).ConvertFrom(Value)

TypeDescriptoradalah metode GetConvertoryang memiliki kelas yang menerima Typeobjek dan kemudian Anda dapat memanggil ConvertFrommetode untuk mengonversi objek valueyang ditentukan.

Dinesh Rathee
sumber
Saya pribadi berpikir antarmuka ini lebih baik untuk menangani konversi daripada metode Convert.ChangeType karena Anda perlu mengimplementasikan antarmuka IConvertible di semua kelas Anda.
Sauleil
3

Anda bisa menggunakan konstruk seperti kelas sifat . Dengan cara ini, Anda akan memiliki kelas pembantu parameterised yang tahu cara mengkonversi string ke nilai jenisnya sendiri. Maka rajin giat Anda akan terlihat seperti ini:

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

Sekarang, saya harus menunjukkan bahwa pengalaman saya dengan tipe parameter terbatas pada C ++ dan templatnya, tapi saya membayangkan ada beberapa cara untuk melakukan hal yang sama menggunakan generik C #.

Greg Hewgill
sumber
Versi generik tidak ada di C #.
Shimmy Weitzhandler
3

Periksa statis Nullable.GetUnderlyingType. - Jika tipe yang mendasarinya adalah nol, maka parameter templatnya tidak Nullable, dan kita bisa menggunakan tipe itu secara langsung - Jika tipe yang mendasarinya bukan nol, maka gunakan tipe yang mendasarinya dalam konversi.

Tampaknya bekerja untuk saya:

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");
}
Bob C
sumber
1

Dengan inspirasi dari jawaban Bob , ekstensi ini juga mendukung konversi nilai nol dan semua konversi primitif kembali dan keempat.

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));
        }
}

Contohnya

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

            int? intValue = null;
            var strResult = intValue.Convert<string>();
Ghominejad
sumber
0
public class TypedProperty<T> : Property
{
    public T TypedValue
    {
        get { return (T)(object)base.Value; }
        set { base.Value = value.ToString();}
    }
}

Saya menggunakan konversi melalui suatu objek. Ini sedikit lebih sederhana.

Mastahh
sumber
terima kasih saya harus mengonversi T dalam antarmuka dan objek T konversi sederhana bekerja dengan benar, mudah dan cepat terima kasih
LXG
5
(int) (objek) "54"; adalah FATALITAS !, ini bukan VB!
Tomer W
0

Saya menggunakan jawaban lobos dan berfungsi. Tapi saya punya masalah dengan konversi ganda karena pengaturan budaya. Jadi saya menambahkan

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

Namun variasi lain. Menangani Nullables, serta situasi di mana string adalah nol dan T tidak dapat dibatalkan.

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(); }
    }
}
Todd Menier
sumber
0

Anda dapat melakukannya dalam satu baris seperti di bawah ini:

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

Selamat coding;)

Hemendra
sumber
Ketika Anda membagikan kode sebagai jawaban, coba jelaskan.
Yunus Temurlenk