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

现在假设一个具体的 Wrapper:

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

我想这样调用Wrap扩展:

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

这是不可能的,因为在 c# 中我们需要为Wrap扩展提供两个类型参数。(全有或全无)

显然,在 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# 中使用它?

当然,但是如果您Wrap从 C# 调用,您将返回 C# 类型推断,并且必须指定第二个类型参数。

于 2012-12-27T18:21:05.853 回答
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 回答
3

您可以在 F# 中执行此操作:

open System.Runtime.CompilerServices

type Wrapper<'T> =
  abstract Wrapped : 'T

[<Extension>]
module WrapperExtensions =

  [<Extension>]
  let Wrap wrapped = { new Wrapper<_> with member x.Wrapped = wrapped }

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

然后像这样从 C# 使用它:

var wrapped = 42.Wrap();
wrapped.Unwrap();

那是你要的吗?

于 2012-12-27T18:15:46.927 回答
3

您可以使用帮助器类将通用参数分成两个单独的调用,从而推断出您想要的参数。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 回答