使用策略模式在C#上实现多参数C++模板行为

xva*_*van 8 c# generics extension-methods template-specialization implicit-conversion

我正在尝试使用C#泛型和基于此答案的策略模式实现类似c ++的模板

这是模式的一个示例:

interface ISomePolicy<T,U>
{
    void _doSomething(U u);
}


class MyClass<T,U>:
     ISomePolicy<int, double>,
     ISomePolicy<int, int>
    {

    internal T myElement {get;set;}

    public MyClass(T Element) {
        myElement = Element;
    }

    void ISomePolicy<int, double>._doSomething(double u)
    {
        Console.WriteLine("this is int, double");
    }

    void ISomePolicy<int, int>._doSomething(int u)
    {
        Console.WriteLine("this is int, int");
    }

    }

static class MyClassExtension
{

    //What I want to do
    public static void doSomething<P, T, U>(this P oTh, U u) where P : MyClass<T, U>, ISomePolicy<T, U>
    {
        oTh._doSomething(u);
    }

}
Run Code Online (Sandbox Code Playgroud)

我的预期行为是这样的:

  MyClass<int, double> oClass = new MyClass<int, double>(3);

  oClass.doSomething(0.5); //This works
  oClass.doSomething(1);   //This works

  oClass.doSomething("This should fail"); //Breaks at compile time           

  MyClass<string, double> oClass1 = new MyClass<string, double>("sadfsd"); //Not implemented, wasn't able to prevent the construction.

  oClass1.doSomething(0.4); //Breaks at compile time
Run Code Online (Sandbox Code Playgroud)

但到目前为止,我无法使.net接受通用扩展,参数少于参数

我可以明确地调用接口,这是一个可怕的冗长,打败了所有这一切的目的.

oClass.doSomething < MyClass<int, double>,int,double>(0.5);
Run Code Online (Sandbox Code Playgroud)

我想用包装器来解决这个问题:

static class MyClassExtension{
    private static void wrappedDoSomething<P, T, U>(this P oTh, U u) 
    where P : MyClass<T, U>, ISomePolicy<T, U>
    {
        oTh._doSomething(u);
    }

    public static void doSomething<T, U>(this MyClass<T, U> oTh, U u)

    {
        oTh.wrappedDoSomething<MyClass<T, U>, T, U>(u);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是包装器不能解析包装函数的两种类型,但是失败了:

错误1类型'MyClass'不能用作泛型类型或方法'MyClassExtension.wrappedDoSomething(P,U)'中的类型参数'P'.没有从"MyClass"到"ISomePolicy"的隐式引用转换

任何有关修复参数问题或重新设计所有这些的见解都表示赞赏.


对于上下文,这将用于包装I/O转换器.T在我的例子中将是目标I/O格式,以及U我的框架使用的数据的对象表示.

我知道这可以通过委托或接口轻松实现,但目标是框架用户可以轻松实例化所需的转换,如果实现不存在,则可以简单地将其添加到公共接口.


编辑:从另一个泛型方法/类内部解析泛型方法似乎既不适用于单声道.

Ser*_*dar 3

Usually, policies should not contain data. For example,

interface ISomePolicy<T, U>
{
    void _doSomething(T t, U u);
}

struct SomePolicyImplementation :
    ISomePolicy<int, double>,
    ISomePolicy<int, int>,
    ISomePolicy<double, double>
{
    void ISomePolicy<int, int>._doSomething(int t, int u)
        => Console.WriteLine("this is int, int");

    void ISomePolicy<int, double>._doSomething(int t, double u)
        => Console.WriteLine("this is int, double");

    void ISomePolicy<double, double>._doSomething(double t, double u)
        => Console.WriteLine("this is double, double");
}

static class SomePolicyExtension
{
    public static void doSomething<P, T, U>(this P policy, T t, U u)
        where P : struct, ISomePolicy<T, U>
        => policy._doSomething(t, u);
}
Run Code Online (Sandbox Code Playgroud)

If you would like to combine policies and data then you may consider different interface

interface IEmbeddedPolicy<U>
{
    void _doSomething(U u);
}

class MyClass<T> :
    IEmbeddedPolicy<double>,
    IEmbeddedPolicy<int>
{
    public T Value { get; }

    public MyClass(T value) { this.Value = value; }

    void IEmbeddedPolicy<int>._doSomething(int u)
        => Console.WriteLine("this is T, int");

    void IEmbeddedPolicy<double>._doSomething(double u)
        => Console.WriteLine("this is T, double");
}

static class EmbeddedPolicyExtension
{
    public static void doSomething<E, U>(this E embedded, U u)
        where E : IEmbeddedPolicy<U>
        => embedded._doSomething(u);
}
Run Code Online (Sandbox Code Playgroud)

Or combination of these two concepts

class MySuperClass<P, T>:
    IEmbeddedPolicy<double>,
    IEmbeddedPolicy<int>
    where P: struct, ISomePolicy<T, double>, ISomePolicy<T, int>
{
    public T Value { get; }

    public MySuperClass(T value) { this.Value = value; }

    void IEmbeddedPolicy<int>._doSomething(int u)
        => new P()._doSomething(this.Value, u);

    void IEmbeddedPolicy<double>._doSomething(double u)
        => new P()._doSomething(this.Value, u);
}
Run Code Online (Sandbox Code Playgroud)

Usage:

// independent policy
var policy = new SomePolicyImplementation();

policy.doSomething(5, 6);
policy.doSomething(5, 6.7);
policy.doSomething(5.3, 6.7);

// embedded policy
var my = new MyClass<int>(54);
my.doSomething(5);
my.doSomething(89.7);

// combination
var x = new MySuperClass<SomePolicyImplementation, int>(53);
x.doSomething(9);
x.doSomething(18.3);
Run Code Online (Sandbox Code Playgroud)