1

以下の拡張メソッドを指定します。

public static class Ext
{
    public static void Serialize(this Guid guid_, StringWriter sw_)
    {
        sw_.Write(guid_.ToString("B"));
    }
}

そしてクラス:

public class Field<T>
{
    public T value;

    public void Serialize(StringWriter sw_)
    {
        value.Serialize(sw_);
    }
}

次のことをしたいのですが、よくわかりません。

public class Foo
{
    public Field<Guid> uid;

    public Foo()
    {
        // assume StringWriter object sw;
        uid.Serialize(sw);
    }
}

明らかに、実際の状況はもっと複雑です。これは必要最小限の例にすぎません。

編集

コンパイラ エラー:

エラー CS1928: 'T' には 'Serialize' の定義が含まれておらず、最適な拡張メソッド オーバーロード 'Ext.Serialize(System.Guid, StringWriter)' に無効な引数が含まれています

エラー CS1929: インスタンス引数: 'T' から 'System.Guid' に変換できません

4

4 に答える 4

1

Tコンパイル時にそうであるかどうかが確実にわからないためGuid、不可能です。

しかし、あなたはこのようなことをすることができます

public class GuidField : Field<Guid>
{
    public override void Serialize(StringWriter sw_)//Assume we have made base class method virtual
    {
        value.Serialize(sw_);
    }
}

これは、C# コンパイラがvalueコンパイルGuid時に認識しているため、機能します。


次の方法は機能しますが、「ジェネリック」のポイントを無効にします。もお勧めしません。方法を示すために、例を挙げます

public void Serialize(StringWriter sw_)
{
    if (typeof (T) == typeof (Guid))
    {
        ((Guid)(object)value).Serialize(sw_);
    }
}
于 2013-11-14T08:34:44.873 に答える
1

T「拡張メソッドが定義されているタイプのみになる」などの制限を適用する方法はありません。

これに本当にジェネリックを使用する必要がある場合は、次のように、シリアル化できる型ごとにアダプターを作成する必要があります。

public static class Ext
{
    public static void Serialize(this Guid guid_, StringWriter sw_)
    {
        sw_.Write(guid_.ToString("B"));
    }
}

public class Field<T> where T: ISerializableField
{
    public T value;

    public void Serialize(StringWriter sw_)
    {
        value.Serialize(sw_);
    }
}

public interface ISerializableField
{
    void Serialize(StringWriter sw);
}

public class SerializableGuid : ISerializableField
{
    private readonly Guid _guid;
    public SerializableGuid(Guid guid)
    {
        _guid = guid;
    }
    public void Serialize(StringWriter sw)
    {
        _guid.Serialize(sw);
    }
}

このアダプターは、特定の型のインスタンスをラップし、それをシリアル化する方法を公開します。はアダプターのインスタンスでのみ機能するようになったことTに注意してください。すべてのインスタンスをシリアル化できることが確実にわかっています。Field<T>ISerializableFieldField<T>T

その点で、拡張メソッドはもう必要ありません。アダプター自体がシリアル化を実行できます。コードの他の部分でも GUID をシリアル化する場合を除きます。

編集

シリアル化できる型ごとにクラスを作成することを避けることが最優先事項であり、型の安全性を失うことを気にしない場合は、動的呼び出しを使用できます。

public class Field
{
    private dynamic Value { get; set; }

    public void Serialize(StringWriter sw)
    {
        try
        {
            Value.Serialize(sw);
        }
        catch (RuntimeBinderException ex)
        {
            throw new InvalidOperationException(string.Format("Instance of type {0} does not implement a Serialize method", Value.GetType()), ex);
        }
    }
}

ジェネリックはもう必要ありません。ジェネリックスは型安全性を強制しますが、それは破棄します。

于 2013-11-14T08:37:27.650 に答える
0

Field クラスの問題は、T がジェネリック型であり、この時点では「不明」であるため、拡張メソッドは GUID の具象型であるため、拡張メソッドは表示されません。T が GUID であるかどうかを確認する必要があるかもしれません。そうであれば、拡張メソッドを呼び出すことができる GUID にキャストする必要があります。そのため、コンパイルされるかどうかもわかりません。

クラス Foo の最後の例については、uid は GUID ですか? その場合、Ext クラスが存在するプロジェクトと名前空間をインポートしましたか? そうでない場合は、表示されるはずです。

于 2013-11-14T08:29:18.640 に答える