Внедрение многопараметрического шаблона С++, как поведение на С# с использованием шаблона политики

Я пытаюсь реализовать шаблон типа С++ с общим набором С# и шаблоном политики на основе этого ответа

Это образец шаблона:

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

}

Мое предполагаемое поведение выглядит следующим образом:

  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

Но пока я не смог сделать .net accept Generic Extension с меньшими аргументами, чем параметры

Я могу вызвать интерфейс явно, что является ужасным подробным, преследующим цель всего этого.

oClass.doSomething < MyClass<int, double>,int,double>(0.5);

Я думал о том, чтобы работать с оберткой:

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

Но оболочка не может разрешить оба типа для завернутой функции, не выполнив следующие действия:

Ошибка 1 Тип "MyClass" не может использоваться как параметр типа "P", в общем типе или методе 'MyClassExtension.wrappedDoSomething(P, U)'. Здесь нет неявное преобразование ссылок из "MyClass" в 'ISomePolicy'

Любые идеи для исправления проблемы параметров или реорганизации всего этого оцениваются.


Для контекста это будет использоваться для переноса переводчиков ввода-вывода. T в моем случае будет целевым форматом ввода/вывода, а U - представлением объекта для данных, используемых моей каркасом.

Я знаю, что это может быть легко достигнуто с помощью делегатов или интерфейсов, но цель заключается в том, что пользователь фреймворка легко создает требуемый перевод, а если реализация не существует, его можно добавить тривиально в общий интерфейс.


EDIT: разрешение универсального метода из другого общего метода/класса не работает на моно.

Ответ 1

Обычно политики не должны содержать данные. Например,

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

Если вы хотите объединить политики и данные, вы можете рассмотреть другой интерфейс

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

Или сочетание этих двух понятий

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

Использование:

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

Ответ 2

Пробовал ваш код, но даже простые вызовы не работали из коробки. Основная проблема заключается в том, что MyClass содержит неизвестный тип элемента 'myEement' - этот тип не может быть выведен из параметров вызова функции. Однако, если вы делаете обобщение и опускаете тип объекта, ваш образец будет работать вне поля:

using System;
using System.Collections.Generic;

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

public class MyClass<U> :
     ISomePolicy<double>,
     ISomePolicy<int>
{
    internal object myEement { get; set; }

    public MyClass(object Element)
    {
        myEement = Element;
    }

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

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

static class MyClassExtension
{
    public static void doSomething<P, U>(this P oTh, U u) where P : ISomePolicy<U>
    {
        oTh._doSomething(u);
    }
}

class Program
{
    static void Main()
    {
        MyClass<double> oClass = new MyClass<double>(3);
        oClass.doSomething(0.5); //This works
        oClass.doSomething(1);   //This works            
        //oClass.doSomething("Will not work");
    }
}

Что такое myEement (или вы, вероятно, подразумевали myElement) - вы можете получить его тип во время выполнения, если это необходимо.

myElement.GetType(), or cast to it - e.g.
if( myElement is int ) DoSomethingWithInt( (int) myElement );

Однако отражение всегда может замедлить выполнение. Если вы не собираетесь создавать иерархию супер тяжелого класса с огромным количеством экземпляров - тогда этого должно быть достаточно для ваших нужд.