0

So I have a very big Generic class 1500+ rows and growing, with loads of methods. It has CrazyMethods and GoodMethods, I want to put the different kinds of methods in their own class but still be able to use my generic as if they were inside the generic class.

public class MyGeneric<T> : IMyGeneric<T> where T : IEntity
{
    public MyGeneric(string stuff)
    {
        moreStuff(stuff);
    }
    // Region Good
    public void MyGoodMethod1(T entity)
    {
      //does good stuff with the generic..
    }
    public T MyGoodMethod2()
    {
      //does other good stuff with the generic..
    }

    //Region Crazy
    public void MyCrazyMethod1(T entity)
    {
      //does crazy stuff with the generic..
    }
    public T MyCrazyMethod2()
    {
      //does other crazy stuff with the generic..
    }
}

Now in my other project where I use this generic it looks something like this

...
SomeObject _myObject =  new MyGeneric<SomeObject>("ladida");

_myObject.MyGoodMethod1();
//..Other stuff
_myObject.MyCrazyMethod2();¨
...

How do I separate the methods from the MyGeneric class into separate classes (MyGenericGoodMethods.cs, MyGenericCrazyMethods.cs) but still be able to use them the way I showcased above ?

If I could use extension methods for generics that would be the perfect solution.

public static class MyGenericGoodMethods<T> where T : IEntity
{
    public static T Method2(this MyGeneric<T> generic)
    {
        //does other good stuff with the generic..
    }
}

but

Extension method can only be declared in non generic, non nested, static class

user3621898
  • 589
  • 5
  • 24

3 Answers3

3

You can declare extension method in normal static class and use it with generic.

public static class MyGenericGoodMethodsExtensions
{
    public static T Method2(this MyGeneric<T> generic)
    {
        //does other good stuff with the generic..
    }
}

var myGeneric = new MyGeneric<string>();
myGeneric.Method2()

But you can always split your giant class in many separated generic classes and use them inside your main-generic class.

Split up your interfaces

public interface IMyGeneric<T>
{
    void MyGeneric(string stuff);
}

public interface IMyGoodGeneric<T>
{
    void MyGoodMethod1(T entity);
    void MyGoodMethod2(T entity);
}

public interface IMyCrazyGeneric<T>
{
    void MyCrazyMethod1(T entity);
    void MyCrazyMethod2(T entity);
}

Introduce separated implementation

public class MyGeneric<T> : IMyGeneric<T> where T : IEntity
{
    public void MyGeneric(string stuff)
    {
        // implementation
    }
}

public class MyGoodGeneric<T> : IMyGoodGeneric<T> where T : IEntity
{
    public void MyGoodMethod1(T entity) {}
    public void MyGoodMethod2(T entity) {}
}

public class MyCrazyGeneric<T> : IMyCrazyGeneric<T> where T : IEntity
{
    public void MyCrazyMethod1(T entity) {}
    public void MyCrazyMethod2(T entity) {}
}

Then you can create your "giant" composition class which will implement all interfaces and use already existed implementations

public class MyGiantGeneric<T> : IMyGeneric<T>,
                                 IMyGoodGeneric<T>,
                                 IMyCrazyGeneric<T> where T : IEntity
{
    private readonly IMyGeneric<T> _myGeneric;
    private readonly IMyGoodGeneric<T> _myGoodGeneric;
    private readonly IMyCrazyGeneric<T> _myCrazyGeneric;

    public MyGiantGeneric(IMyGeneric<T> myGeneric,
                          IMyGoodGeneric<T> myGoodGeneric,
                          IMyGCrazyGeneric<T> myCrazyGeneric)
    {
        _myGeneric = myGeneric;
        _myGoodGeneric = myGoodGeneric;
        _myCrazyGeneric = myCrazyGeneric;
    }

    public void MyGeneric(string stuff)
    {
        _myGeneric.MyGeneric(stuff);
    }

    public void MyGoodMethod1(T entity) 
    {
        _myGoodGeneric.MyGoodMethod1(entity);
    }

    // and so on...
}    

With this approach your logic will stay in logically separated classes.
In case somewhere you need only MyGoodGeneric method you don't need to provide whole giant class and will provide only the part needed.

In case some where you want introduce another implementation only for the MyCrazy methods you will not be forced to implement MyGood methods which you don't need in this case.

Fabio
  • 31,528
  • 4
  • 33
  • 72
  • Interfaces don't expose constructors. – kall2sollies Jan 07 '17 at 01:44
  • @kall2sollies - what you mean? – Fabio Jan 07 '17 at 01:45
  • Thank you for trying Fabio, but I really don't want to create additional interfaces. Partial classes were what I needed. Your solution would still require additional code for every method inside my big generic. – user3621898 Jan 07 '17 at 01:47
  • @user3621898 - I want to answer your question because I noticed you using `regions` which are good sign to separate logic to different classes. Does you have local variables in the class which used for example only for `Crazy` methods? If so the it is another very good sign to separate class. Classes in OO programming are developer's tools and their cannot be more or less. – Fabio Jan 07 '17 at 01:55
  • @Fabio I though your void MyGeneric(string stuff) method was a constructor signature in the interface, but I read too fast, my bad ! – kall2sollies Jan 09 '17 at 00:52
0

So Partial classes were exactly what i was looking for. Thanks to @BradleyDotNET and @AliAbdelfattah

public partial class MyGeneric<T> : IMyGeneric<T> where T : IEntity
{
    public MyGeneric(string stuff)
    {
        moreStuff(stuff);
    }
   //.. other stuff
}

in MyGenericGood.cs

public partial class MyGeneric<T> where T : IEntity
{
    public void MyGoodMethod1(T entity)
    {
      //does good stuff with the generic..
    }
    public T MyGoodMethod2()
    {
      //does other good stuff with the generic..
    }
}
user3621898
  • 589
  • 5
  • 24
0

Extension method can be generic, not its container class:

public static class Extensions
{
    public static T Method2<T>(this MyGeneric<T> generic)
    {
    }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433