4

これはこの質問に関連しています。

ジェネリック ラッパー クラスを作成したい:

public abstract class Wrapper<T>
{
    internal protected T Wrapped { get; set; }
}

次の拡張子を使用します。

public static class WrapperExtensions
{
    public static W Wrap<W,T>(this T wrapped) where W:Wrapper<T>,new()
    {
        return new W {Wrapped = wrapped};
    }

    public static T Unwrap<T>(this Wrapper<T> w)
    {
        return w.Wrapped;
    }
}

ここで、具体的なラッパーを想定します。

public class MyIntWrapper : Wrapper<int>
{
    public override string ToString()
    {
        return "I am wrapping an integer with value " + Wrapped;
    }
}

Wrap次のように拡張機能を呼び出したいと思います。

MyIntWrapper wrapped = 42.Wrap<MyIntWrapper>(); 

WrapC# では両方の型引数を拡張機能に提供する必要があるため、これは不可能です。(オールオアナッシングです)

どうやら、F# では部分的な推論が可能です。

上記のコードは F# ではどのように見えるでしょうか?

C#から使えますか?

4

4 に答える 4

4

どうやら、F# では部分的な推論が可能です。

はい、あなたの例では W だけを指定する必要があります。T が推測されます。


上記のコードは F# ではどのように見えるでしょうか?

[<AbstractClass>]
type Wrapper<'a>() =
    [<DefaultValue>]
    val mutable internal Wrapped : 'a

let Wrap<'W,'T when 'W :> Wrapper<'T> and 'W: (new: unit -> 'W)> (wrapped: 'T): 'W = 
    let instance = new 'W()
    instance.Wrapped <- wrapped
    instance

let Unwrap (w: Wrapper<_>) = w.Wrapped

type MyIntWrapper() =
    inherit Wrapper<int>()
    override this.ToString() = 
        sprintf "I'm wrapping an integer with value %d" this.Wrapped

そして、この方法で F# インタラクティブから Wrap を呼び出すことができます

> let wrapped = Wrap<MyIntWrapper,_> 5;;
val wrapped : MyIntWrapper = I'm wrapping an integer with value 5

私の意見では、これは F# ではあまり慣用的ではありません。ラップ/アンラップには判別共用体とパターン マッチングを使用したいと思いますが、具体的なケースが何であるかは正確にはわかりません。


C#から使えますか?

確かに、しかし、WrapC# から呼び出す場合は、C# の型推論に戻り、2 番目の型パラメーターを指定する必要があります。

于 2012-12-27T18:21:05.853 に答える
3

ヘルパークラスを使用して、汎用パラメーターを2つの別々の呼び出しに分割し、必要なものを推測できるようにすることができます。LinqPadサンプル:

void Main()
{
    MyIntWrapper wrapped = 42.Wrap().To<MyIntWrapper>(); 
}

public abstract class Wrapper<T>
{
    internal protected T Wrapped { get; set; }
}

public static class WrapperExtensions
{
    public static WrapHelper<T> Wrap<T>(this T wrapped) 
    {
        return new WrapHelper<T>(wrapped);
    }

    public static T Unwrap<T>(this Wrapper<T> w)
    {
        return w.Wrapped;
    }

    public class WrapHelper<T> 
    {
        private T wrapped;

        public WrapHelper(T wrapped) 
        {
            this.wrapped = wrapped;
        }

        public W To<W>() where W : Wrapper<T>, new() 
        {
            return new W {Wrapped = wrapped};
        }
    }
}

public class MyIntWrapper : Wrapper<int>
{
    public override string ToString()
    {
        return "I am wrapping an integer with value " + Wrapped;
    }
}

WrapHelper<T>特に、メソッドを公開する新しいクラスに注目してTo<W>ください。そのメソッドには明示的なジェネリック引数を渡しますが、元のWrap<T>メソッドには、そのヘルパークラスのインスタンスを返すことで推測されthis T、メソッド呼び出しをチェーンして必要なものを取得できます。

于 2012-12-27T18:18:22.320 に答える
3

カスタムの暗黙的な変換を実装します。

MSDN サンプル

struct MyIntWrapper
{
    public MyIntWrapper(int value) 
    {
        this.value = value; 
    }

    static public implicit operator MyIntWrapper(int value)
    {
        return new MyIntWrapper(value);
    }

    static public explicit operator int(MyIntWrapper wrapper)
    {
         return wrapper.value;
    }

    private int value;
}

次に、次のように記述できます。

MyIntWrapper wrapped = 42;
于 2012-12-27T17:58:48.443 に答える