views:

565

answers:

3

I have a bunch of data I want to instantiate in a class, and for each variable I want to ensure a specific set of methods are also defined. IE:

[TypeA] VarA
[TypeB] VarB
[TypeC] VarC

FA1() which is a function of VarA and VarB
FA2() which is a function of VarA and VarC

FB1() which is a function of VarB and VarA
FB2() which is a function of VarB and VarC
...

As there will be a large number of variables (and hence even more functions) I want to split my source code up into manageable chunks. So I am looking for an automatic way of ensuring that all of the functions for each variable are instantiated.

I have come up with 3 possible methods to organize my code and I am not too happy with each of them and I am looking or advice as to which method is the better (or even if I have missed a completely different implementation method):

1. Partial Class

partial class Base
{
}

partial class Base 
{
  [TypeA] VarA;

  FA1 { .. };  // function of VarA and VarB
  FA2 { .. };  // function of VarA and VarC
}


partial class Base 
{
  [TypeB] VarB;

  FB1 { .. };  // function of VarB and VarA
  FB2 { .. };  // function of VarB and VarC
}

Pros:

  1. Simple
  2. Variables can only be accessed from within class Base.
  3. If there are two variables of the same type then the functions for each variable can implement its own function differently.

Cons:

  1. Cannot automatically ensure that all functions are created for each variable
  2. Need to manually ensure that there are no name collisions between each function name.

Note that the Cons may be solved by a code generator of some sort (maybe time to learn T4??)


2. Internal class

class Base 
{
  internal [ClassA] ObjA = new [ClassA]();
  internal [ClassB] ObjB = new [ClassB]();
}

class [BaseClassA]
{
  public [TypeA] VarA;

  public virtual F1 { .. };
  public virtual F2 { .. };
}

class [ClassA] : [BassClassA]
{
  public override F1 { .. };  // function of VarA and ObjB.VarB
  public override F2 { .. };  // function of VarA and ObjC.VarC
}
...

Pros:

  1. Class hierarchy enforces that all functions are created and that variables are there to be accessed.
  2. Through use of virtual functions can create instance specific implementations of functions

Cons:

  1. Use of Internal means that data is visible everywhere in the assembly.


3. Static data

abstract class Data
{
   static [TypeA] VarA;
   static [TypeB] VarB;
   ...
}

abstract class [BaseClassA] : Data
{
  public virtual F1 { .. };
  public virtual F2 { .. };
}

class [ClassA] : [BassClassA]
{
  public override F1 { .. };  // function of VarA and VarB
  public override F2 { .. };  // function of VarA and VarC
}

class Base 
{
 [ClassA] ObjA = new [ClassA]();
 [ClassB] ObjB = new [ClassB]();
}

Pros:

  1. System ensures that all routines are instantiated
  2. Data is not blasted all around the assembly
  3. Within each function you can directly reference the other variables as per the 'partial class' solution

Cons:

  1. The use of static smells like I have just re-invented global data.


What I want is to somehow cherry pick the best points of each method:

  1. The direct manner of accessing variables of the "Partial class" and "Static" methods
  2. The local data of the "Partial class" method
  3. The automatic enforcing of function implementation of the "Internal" and "Static" methods.

And I want to avoid:

  1. The lack of enforcing function generation in the "Partial class"
  2. The global access of data in the "Internal" method
  3. The re-invention of global data in the "Static" method

If I was going to have my druthers I'd say that what I want is to somehow apply an interface to an instance of a variable - like:

[TypeA] VarA : IFunctions;
[TypeB] VarB : IFunctions;

And somehow have the compiler auto-generate the final function names from the interface names and the vaiable name.

So can people suggest which of the 3 methods they would prefer to implement, or suggest any other methods that may suit.

A: 

Your question is largely without any real context and is difficult to understand. You have provided three "answers" without a clear question (imo.)

Frankly, if you want to ensure that each "variable" as you call it has associated methods, you should consider using interfaces, and use properties in the place of fields (since interfaces cannot specify fields.)

interface IAStuff {
    TypeA AProp { get; }
    void DoSomethingToA();
}

interface IBStuff {
    TypeB BProp { get; }
    void DoSomethingToB();
}

public class Foo : IAStuff, IBStuff {
    TypeA AProp { get; private set; }
    TypeB BProp { get; private set; }

    void DoSomethingToA() { ... }
    void DoSomethingToB() { ... }
}

If the class declares that it implements an interface, it has no choice but to provide the specified members or it will not compile.

Hope this helps,

-Oisin

x0n
Thanks for the reply, although while I do believe that I have a clear question I am not going to claim that it is necessarily clearly presented :-) But as to your reply I can see where you are coming from, however as written I don't think that it scales well as I have to define an interface for every variable (not just every type of variable) and hence still manually maintain the names of all the methods - something I am hoping to get away from. And I can't see a generic interface helping as that would abstract the types, but not the method names
Peter M
If you replace the variable with a _class_, perhaps a generic interface or base class would do the trick. A wise old coder once told me: if you can't make it work, add more classes ;-)
x0n
to clarify, I mean factor out the field.
x0n
I think adding classes will put me into the realm of of solutions #2 or #3 that I proposed. I'm not sure but think that a code generator may be the best solution in this case.
Peter M
A: 

Could you not use suggestion 2 but with protected instead of internal?

ICR
My initial reaction is no. Protected allows access to members from classes that are derived from the base class. However in this case I am using composition and are not deriving ClassA and ClassB from Base. As a result both ClassA and ClassB have to be able to be compiled independently from Base and I can't see how to do that without "Internal"
Peter M
+2  A: 

You present four code samples, the 'simple' version so that you can explain the problem and then 3 'better' solutions to fix the problem. The only version that was self-explanatory was the simple version. So, I'm thinking of the poor developer that has to come in a maintain this next year (which might be you after forgetting what you did).

So, could you consider a different mechanism altogether for "ensuring that all of the functions for each variable are instantiated". You mentioned a willingness to use T4 to auto-generate stubs for you during compile time. What about using Microsoft FxCop to catch any instances where you forgot to add something.

If you're not familiar with it, Microsoft FxCop (also embedded in some flavors of Visual Studio) scans the compiled assemblies and evaluates hundreds of framework rules against your code, from proper spelling and casing of variables to unused locals.

While I personally agree with most of the rules that Microsoft has bundled into FxCop, I think the real beauty of it is the ability to create your own rules. I have created rules that I add to FxCop that enforces CRUD principles, such as if you have a CreateXxx method, you must have a DeleteXxx method etc. So, if you identify a class that matches the pattern you desire, you can get a list of all variables {A, B, C} and then guarantee that FuncAB(A, B) exists and that FuncAC(A, C) exists etc.

Then, even a junior developer would be caught out by FxCop the next time he implements IBiVariableFunction and forgets a function on a pair.

Cheers, Adrian

Adrian
Thanks for the reply. I had never considered using FxCop in the manner suggested, but my question is more about not having to manually generate a bunch of code than coming after the fact and having FxCop tell me that "you haven't don't this".As to the complexity of the question. The "simple" version and example #1 are identical - they only differ by the use of partial classes to distribute code over separate files. The other two examples use/abuse simple inheritance to achieve the desired outcome - not something that I would consider needs explaining in depth.
Peter M
Interesting, I just re-reviewed your samples and broke one of my initial assumptions. I was originally thinking that the functions were transitive wrt their arguments. That is FuncAB(...) and FuncBA(...) would have been the same (e.g. addition instead of concatenation), I now see that isn't the case. So, without thinking the answer through, would a generic interface help? Something like IFunc<T, U> which requires Func(T, U) and Func(U, T) to exist? Probably get pretty ugly with lots of interfaces declared...
Adrian
I am not sure a generic interface would do me, but I am ignoring the problem for now.
Peter M