Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintaining a bunch of generic functions

Tags:

c#

generics

Is there a better way to manage a bunch of generic functions? These all have a implementation that look almost the same. Changing them however is a monks job atm.

The interface that's implemented looks like this:

 IProxy<T> AddInterceptor<T1, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, TResult>, T1, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, TResult>, T1, T2, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, TResult>, T1, T2, T3, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, TResult>, T1, T2, T3, T4, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, TResult>, T1, T2, T3, T4, T5, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, TResult>, T1, T2, T3, T4, T5, T6, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, TResult>, T1, T2, T3, T4, T5, T6, T7, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> func);
 IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> func);

Pretty but you can emagine how the implementation looks. And what if I want to change something to the signature of these methods.

like image 306
albertjan Avatar asked Mar 10 '14 13:03

albertjan


3 Answers

Here is possible implementation of T4 template which generates your interface:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#  const int maxParametersCount = 15; #>
using System;
using System.Linq.Expressions;

public interface IInterceptable<T>
{
<# for(int parametersCount = 1; parametersCount <= maxParametersCount; parametersCount++) { 
   string parameters = String.Join(", ", Enumerable.Range(1, parametersCount).Select(i => "T" + i));         
#>    IProxy<T> AddInterceptor<<#= parameters #>, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<<#= parameters #>, TResult>, <#= parameters #>, TResult> func);
<#}#>
}

You need only provide maxParametersCount value. If you will provide 15 it will generate following interface declaration:

using System;
using System.Linq.Expressions;

public interface IInterceptable<T>
{
    IProxy<T> AddInterceptor<T1, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, TResult>, T1, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, TResult>, T1, T2, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, TResult>, T1, T2, T3, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, TResult>, T1, T2, T3, T4, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, TResult>, T1, T2, T3, T4, T5, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, TResult>, T1, T2, T3, T4, T5, T6, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, TResult>, T1, T2, T3, T4, T5, T6, T7, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> func);
    IProxy<T> AddInterceptor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(Expression<Action<T>> functionOrProperty, Func<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> func);
}

Of course, you can add some namespace to generated code.

like image 147
Sergey Berezovskiy Avatar answered Nov 19 '22 00:11

Sergey Berezovskiy


You could use T4 templates to automatically generate code with N number of types. If you need to change slightly implementation, you simply edit your template and regenerate. And if you previously generated for 15, and now need 30, simply change your boundary and regenerate.

The greater question here is design - it's a bit of a suspect as to why this is needed in the first place. It may be worth to re-examine that part.

like image 42
LB2 Avatar answered Nov 18 '22 23:11

LB2


This seems like an ideal use for T4 Templates... If you haven't used them they allow you to write code that generates code. Anything this tedious that seems like a robot could do it - perfect application.

If you change something in the signature you simply change it in the t4 template and your .cs file will be updated automatically with the new signature.

like image 9
Kelly Robins Avatar answered Nov 19 '22 00:11

Kelly Robins