Implementing multiparameter C++ template like behaviour on C# using Policy Pattern

后端 未结 2 1557
春和景丽
春和景丽 2021-01-17 23:40

I\'m trying to implement a c++ like template with C# generics and policy pattern based on this answer

This is a sample of the pattern:

interface ISom         


        
相关标签:
2条回答
  • 2021-01-17 23:46

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

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

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

    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);
    
    0 讨论(0)
  • 2021-01-18 00:01

    Tried your code, but even simple calls did not work out of box. Main problem is that MyClass contains unknown element type 'myEement' - that type cannot be deduced from function call parameters. However - if you make a generalization and omit object type - your sample will work in out of box manner:

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

    What is up to myEement (or you probably meant myElement) - you can get's it's type at run-time if necessary.

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

    However - reflection always might slow down your execution. If you don't intend to create super heavy class hierarchy with huge amount of instances - then this should be sufficient for your needs.

    0 讨论(0)
提交回复
热议问题