文字列からのジェネリック型変換


234

別のクラスの「プロパティ」を保存するために使用したいクラスがあります。これらのプロパティは名前と値を持つだけです。理想的には、型付きのプロパティを追加できるようにして、返される「値」が常に希望する型になるようにします。

タイプは常にプリミティブである必要があります。このクラスは、基本的に名前と値を文字列として格納する抽象クラスをサブクラス化します。このサブクラスは、基本クラスに型の安全性を追加する(そして、いくつかの変換で私を救う)という考えです。

だから、私は(おおよそ)これであるクラスを作成しました:

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

だから問題は:

文字列からプリミティブに戻す「一般的な」方法はありますか?

変換を全面的にリンクする汎用インターフェイスを見つけることができないようです(ITryParsableのようなものが理想的でした!)。


スニペットだけでも、具体的なクラスの例を見てみたいと思います。:)
Jon Limjap 08

基本クラスの関連部分を投稿していただけますか?
JJS 2012

誰もがここで.Net Standard 1.2で動作する答えを得ることができるかどうか疑問に思います:/
Dan Rayson

回答:


374

私があなたの意図を正しく理解したかどうかはわかりませんが、これが役立つかどうか見てみましょう。

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

ストリームをジェネリック型に逆シリアル化する方法を数日間疑問に思っていました。ありがとう:)
トラップ

3
が、私は、同意Convert.ChangeType非常に普遍的で拡張可能なソリューションではありません、それは最も基本的なタイプのために働きます、。より良いものが必要な場合は、このメソッドをTimが提案したような大きなものにラップしたり、別の変換メソッドを完全に使用したりしても問題ありません。
lubos hasko

18
T:IConvertible
MikeTを

5
タイプTはIConvertibleであってはなりませんが、base.Valueのタイプはそうである必要があります。
chapluck

74

lubos haskoのメソッドはnullableに対して失敗します。以下のメソッドはnullableに対して機能します。でも、思いつきませんでした。Googleで見つけました:http : //web.archive.org/web/20101214042641/http : //dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx「Tuna Toksoz」のクレジット

最初の使用法:

TConverter.ChangeType<T>(StringValue);  

クラスは以下の通りです。

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

列挙型とその他の複雑な構造のフォールバック変換オプションを追加しますが、良い呼び出しです。
Tomer W 2012

2
RegisterTypeConverterを使用する理由 コンバーターを事前に登録する必要がありますか?(残念ながらリンクが切れているため、読み上げることができませんでした)
Cohen、

複数の変換の場合は、おそらくtcTypeConverter)を1回だけ作成する必要があります。TypeConverterリフレクションを使用してを検索するため、速度が遅くなりTypeConverterAttributeます。単一のプライベートTypeConverterフィールドを初期化すると、TypeConverter何度も再利用できるはずです。
Kevin P. Rice

正常に動作しますが、Tがの場合object、例外がスローされます。`if(typeof(T).IsPrimitive){return TConverter.ChangeType <T>(StringValue);を使用することで、これを回避することができました。} else {object o =(object)StringValue; 戻る; 使用例の代わりに} `を使用 TConverter.ChangeType<T>(StringValue)
Matt

14

多くのタイプ(integer、double、DateTimeなど)には、静的なParseメソッドがあります。リフレクションを使用して呼び出すことができます。

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)

TypeDescriptorオブジェクトGetConvertorを受け入れるメソッドを持つクラスで、メソッドをType呼び出して指定されたオブジェクトのConvertFromを変換できvalueます。


すべてのクラスにIConvertibleインターフェイスを実装する必要があるため、Convert.ChangeTypeメソッドではなく、このインターフェイスの方が変換の処理に適していると個人的に考えています。
Sauleil、

3

トレイトクラスなどの構成を使用できます。このようにして、文字列を独自の型の値に変換する方法を知っているパラメーター化されたヘルパークラスを作成します。次に、ゲッターは次のようになります。

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

ここで、パラメーター化された型に関する私の経験はC ++とそのテンプレートに限定されていることを指摘しなければなりませんが、C#ジェネリックを使用して同じ種類のことを行う方法があると思います。


一般的なバージョンはC#には存在しません。
Shimmy Weitzhandler 2015

3

静的を確認してくださいNullable.GetUnderlyingType。-基になる型がnullの場合、テンプレートパラメータはnullではなくNullable、その型を直接使用できます。-基になる型がnullでない場合は、変換で基になる型を使用します。

私のために働くようです:

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

Bobの回答からインスピレーションを得て、これらの拡張機能はnull値の変換とすべてのプリミティブ変換を前後にサポートします。

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

            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を変換する必要があり、簡単な変換Tオブジェクトが正しく、簡単かつ迅速に感謝作品
LXG

5
(int)(object) "54"; 致命的です!、これはVBではありません!
Tomer W 2012

0

私はロボ答えを使用し、それは動作します。しかし、カルチャー設定のために、doubleの変換に問題がありました。だから私は追加しました

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

0

さらに別のバリエーション。Nullable、および文字列がnullでTがnullにできない状況を処理します。

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

次のように1行で実行できます。

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

幸せなコーディング;)


回答としてコードを共有した場合は、説明してみてください。
Yunus Temurlenk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.