I'm very new in C# and i need some help to use nested classes on my "Hello World" proyect.
I'm trying to create a class callable using class1.subclass1.function(args...) (to create groups of related functions), and I've done something that is working but I think that is not the best way to do it.
My code needs to share a variable between principal class and nested classes (a db handle), and I'm using and argument at class initialization to do it.
namespace SameAsPrincipal
{
public class class1
{
public SQLiteConnection handle = null;
public _subclass1 subclass = null;
public class1(string db_file)
{
handle = new SQLiteConnection(db_file);
subclass1 = new _subclass1(handle);
}
public _subclass1
{
private SQLiteConnection handle = null;
public _subclass1(SQLiteConnection handle)
{
this.handle = handle;
}
public void function(args...)
{
//Do something here
}
}
}
}
Someone knows a better way to create nested classes and share objects between main and nested?
Thanks!!
I am unclear as to why you would want to use a nested class in this instance. The way you have it written, the subclass is all you need. If you want multiple methods (or as you called them "functions") just add your methods.
Is there some hidden reason you would want to use nested classes here? As a general rule, nested classes are rarely needed.
namespace SameAsPrincipal
{
public class Class1
{
private SQLiteConnection handle;
public Class1(string db_file)
{
handle = new SQLiteConnection(db_file);
}
public int AddRecord(Record record)
{
// use handle to add record and get record Id
return record.Id;
}
public void DeleteRecord(int id)
{
// Use handle to delete record
}
}
}
When you instantiate the object you will pass in your db_file and the connection object will be created. Then every method could use that connection object when they are called. However it is usually a better idea to create the connection for each method when it is called and disposing of the connection as soon as you the operation is completed. This, of course, depends on your operations and if they are transnational. For the most part using a "using" block to instantiate your connection is a good way to use connection objects. The sooner you release the connection the sooner the machine will reuse that connection, you can lookup connection pooling to learn more.
Here is an example method that is using the "using" to add a person using a stored procedure:
public int AddPerson(Person person)
{
using (var connection = new SQLiteConnection(dbFile))
{
connection.Open();
using (var command = new SQLiteCommand("spAddPerson",connection))
{
command.CommandType = CommandType.StoredProcedure;
var idParameter = new SQLiteParameter("#Id", DbType.Int32);
idParameter.Direction = ParameterDirection.Output;
command.Parameters.Add(idParameter);
command.Parameters.AddWithValue("#FirstName", person.FirstName);
command.Parameters.AddWithValue("#LirstName", person.LastName);
command.ExecuteNonQuery();
}
}
return person.Id;
}
edit: In regard to your comment below
A few things:
Use namespaces not a parent class to group classes.
Instead of sub-classes you should just add all the database methods to the database class and create classes to model your objects.
Each class should be in it's own file
The namespace parts are ..[]* I.E. Music class has the namespace YourApplication.YourProject.Models - inside the YourProject project, within a first level folder named Music you will find a file named Music.cs and with in that file you will find your music class. This is not a requirement, the compiler does not care about structure like that. It will only make your life easier when you start to get more code developed.
Here is an example of the code structure I am speaking of (remember each of these sections is it's own file)
Create a folder at the root of your project called Models. In this Models folder create a file named Music.cs
namespace YourApplication.YourProject.Models
{
public class Music
{
public int Id { get; set; }
public string Title { get; set; }
public double Length { get; set; }
public string Artist { get; set; }
public string Album { get; set; }
}
}
In this same (Models) folder create a file called Film.cs
namespace YourApplication.YourProject.Models
{
public class Film
{
public int Id { get; set; }
public string Title { get; set; }
public double Length { get; set; }
public string Director { get; set; }
public string[] Actors { get; set; }
}
}
Now back at the project root (no longer in Models folder) create a new folder called Persistence.
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using YourApplication.YourProject.Models;
namespace YourApplication.YourProject.Persistence
{
public static class DatabaseActions
{
public static string dbFile;
public static Music[] ListMusic()
{
var musicList = new List<Music>();
// database call to get all music
using (var connection = new SQLiteConnection(dbFile))
{
connection.Open();
using (var command = new SQLiteCommand("spGetMusic", connection))
{
var reader = command.ExecuteReader();
// The try finally blocks are not strictly needed as these will are suppose to be called upon disposal
try
{
// loop through records creating music objects
while (reader.Read())
{
var music = new Music();
music.Id = reader.GetInt32(0);
music.Title = reader.GetString(1);
musicList.Add(music);
}
}
finally
{
reader.Close();
connection.Close();
}
}
}
return musicList.ToArray();
}
public static int SaveMusic(Music music)
{
if (music.Id == 0)
{
// database stuff - getting the newly created database id
}
else
{
// database calls to update record
}
return music.Id;
}
public static int SaveFilm(Film film)
{
if (film.Id == 0)
{
// database stuff - getting the newly created database id
}
else
{
// database calls to update record
}
return film.Id;
}
public static Music GetMusic(int id)
{
var music = new Music();
// database call and setting of values on music
return music;
}
public static Film GetFilm(int id)
{
var film = new Film();
// database call and setting of values on music
return film;
}
}
}
Now finally create a file on the root called WorkHarness.cs
using System;
using YourApplication.YourProject.Persistence;
namespace YourApplication.YourProject
{
public class WorkHarness
{
public void Initialize()
{
DatabaseActions.dbFile = "your db file";
}
public void ShowMusicList()
{
// list the id and title so user can select by Id
foreach (var music in DatabaseActions.ListMusic())
{
Console.WriteLine("{0,-10}{1}",music.Id,music.Title);
}
}
public void DisplayMusicItem(int id)
{
var music = DatabaseActions.GetMusic(id);
Console.WriteLine("Title: " + music.Title);
Console.WriteLine("Length: " + music.Length);
Console.WriteLine("Artist: " + music.Artist);
Console.WriteLine("Album: " + music.Album);
}
}
}
Without more context as to what the specific application is, it's hard to tell if it's appropriate or not. I agree with the previous answer that it is generally more correct to have separate classes. Your class B can still take a DB handle reference in its constructor, and class A can even pass it to it. That's fine. It's not so much that they are sharing the variable as that they both have a reference to the same DB handle.
The only time I've ever seen sub/inner classes and not thought it was weird was for like simple data objects that are only ever used within the parent class (although they may be referenced outside). For example, if I made a linked list class, I may choose to have the node class be an inner class. For just grouping functionality, regular classes should do that.
Namespaces can also be used for further grouping. For example, maybe all my text operations are in a "MyApp.Text" namespace, but then they are further grouped into classes like "NumberUtils", "NameUtils", and "ZipUtils".
Instead of nesting the objects, create two classes (at the same scope) and have one use the other, such as this:
public class ClassA
{
public ClassB InstanceOfClassB { get; set; }
public ClassA()
{
InstanceOfClassB = new ClassB();
}
//More code here
}
public class ClassB
{
//Code here
}
Using Nested classes in a HelloWorld project? Not a good sign!!
I would suggest not to use nested types Unless you know what you're doing and you have very good explanation to give when asked. Also a note of advice by .NET Framework Guidelines which explicitly recommend against creating public nested classes.
For data sharing in Object oriented programming we have inheritance feature which is the best way to share data/members access across classes based on relationship/association.
to create groups of related functions
As #Nex Terren suggested (with a little modification), you can do something like this, here your Principle class will work as Factory and different classes will provide Aggregation of related functions by their instance
public class PrincipleClass
{
public ClassB InstanceOfClassB { get; private set; }
public ClassA InstanceOfClassA { get; private set; }
public PrincipleClass(string db_file)
{
InstanceOfClassA = new ClassA(new SQLiteConnection(db_file));
InstanceOfClassB = new ClassB();
}
//More code here
}
public class ClassA
{
public ClassA(SQLiteConnection handle)
{
// your code here
}
public void FunctionOfA1() { }
public void FunctionOfA2() { }
}
public class ClassB
{
public void FunctionOfB1() { }
public void FunctionOfB2() { }
}
Now you'll have your group of function together like
new PrincipleClass.InstanceOfClassA.FunctionOfA1();
new PrincipleClass.InstanceOfClassB.FunctionOfB1();
Note - This may also not be a best solution but this is way better than using Nested types.
Related
I have two classes: ImportBase.cs (Parent) and ImportFleet.cs (Child) which will in the future import a CSV file. Each child of ImportBase will implement a different implementation of the actual import code.
The approriate child class to use is determined in a Service class where the correct class is instantiated and the import method called. All is going well up until this point.
The problem is that I also want to Dependency Inject some repository classes into ImportBase and it's inherited classes (as I have attempted in the code below):
ImportBase.cs
namespace WebApi.Services.Import.Investments
{
interface IImport
{
public void Import(IFormFile file, int UserId);
}
public abstract class ImportBase : IImport
{
public abstract void Import(IFormFile file, int UserId);
protected List<InvestmentTransactionType> transactionTypes = new();
protected IInvestmentEntityRepository _investmentEntityRepository;
public ImportBase(IInvestmentEntityRepository investmentEntityRepository)
{
_investmentEntityRepository = investmentEntityRepository;
}
}
}
ImportFleet.cs
namespace WebApi.Services.Import.Investments
{
public class ImportFleet : ImportBase
{
public ImportFleet(IInvestmentEntityRepository investmentEntityRepository) : base(investmentEntityRepository)
{
}
public override void Import(IFormFile file, int UserId)
{
}
}
}
InvestmentService.cs
namespace WebApi.Services
{
public interface IInvestmentService
{
public void Import(IFormFile file, int UserId, int InvestmentEntityId);
}
public class InvestmentService: IInvestmentService
{
public void Import(IFormFile file, int UserId, int InvestmentEntityId)
{
IImport importService = null;
string investmentEntity = ImportBase.determineInvestmentEntityFromCsv(file);
switch(investmentEntity)
{
case "fleet":
importService = new ImportFleet(); // problem is here
break;
}
if (importService != null)
{
importService.Import(file, UserId);
}
}
}
}
The problem is the following line:
importService = new ImportKuflink();
Because I only determine which child class to instantiate at run time, I cannot take advantage of DI here.
Under normal circumstances I would make the Import classes a DI based service so all dependencies are available, however I have to create the instance at run time so this I don't think is possible.
Is there a way to accomplish the above?
Here's a simplified version of your code that demonstrates how you can populate an instance of an object from a DI service container.
In your InvestmentService:
Inject the IServiceProvider.
Use the little known utility ActivatorUtilities to get a fully DI'd instance of your object.
Make sure you dispose it properly if it implemenents IDisposable. I've included an async version if you use anything that needs a IAsyncDisposable.
public class InvestmentService : IInvestmentService
{
private IServiceProvider _serviceProvider;
public InvestmentService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
//...
}
public Import()
{
IImport? importService = null;
IDisposable? disposable = null;
var importFleet = ActivatorUtilities.CreateInstance<ImportFleet>(_serviceProvider);
if (importFleet is IDisposable)
disposable = importFleet as IDisposable;
importService = importFleet as IImport;
// Do whatever you want to do with it
disposable?.Dispose();
}
public async ValueTask ImportAsync()
{
IImport? importService = null;
IDisposable? disposable = null;
IAsyncDisposable? asyncDisposable = null;
var importFleet = ActivatorUtilities.CreateInstance<ImportFleet>(_serviceProvider);
if (importFleet is IDisposable)
disposable = importFleet as IDisposable;
if (importFleet is IAsyncDisposable)
asyncDisposable = importFleet as IAsyncDisposable;
importService = importFleet as IImport;
// Do whatever you want to do with it
disposable?.Dispose();
if (asyncDisposable is not null)
await asyncDisposable.DisposeAsync();
}
}
Yes, of course there is a way to accomplish this. But I guess the DI container you are using (like from MS) won't help you here.
I've been fiddling with crap like this for like two years so far and still am busy with it. Two years of creating my own IoC framework.
Usual DI/IoC microkernels follow OCP and other really mandatory concepts and patterns. What I've done is leaving one single small door open. I won't bore you with details. The fundamental idea is that a class must be decorated with the appropriate attributes in code, and then is able to call the microkernel within its constructor (which has been called by a simple "var foo = new Barney();") to let an entity be modified like it had been created by the microkernel.
There is no(t yet a) way to hook into the plain new() code. Some cheer this, some don't. I'm with the cheerleaders here. Why? Side-effects.
Imagine this:
public class SomeNumber
{
public int SomeValue { get; private set; }
public SomeNumber()
{
SomeValue = 19;
}
}
Okay? Let's assume you'd modified the new() process by whatever, then another user of your code goes:
Assert.AreEqual(19, someNumberEntity.SomeNumber);
and this code throws an exception, because for whatever reason your modifying code set the number to 7.
Now look at this code (from a unit test):
using System.Reflection;
using Kis.Core.Attributes;
namespace UnitTests_Kis.Core
{
[KisAware]
public class KisAwareSimpleClass
{
[Property(value: 123)]
public int ValueToCheck { get; set; } = 0;
[Property(value: "I am the doctor!")]
public string Name { get; set; } = "";
public KisAwareSimpleClass()
{
var t = this.GetType();
var fqtn = t.FullName;
var ec = new Kis.Core.EntityCreator(Assembly.GetAssembly(t));
ec.ModifyExistingEntity(fullyQualifiedTypeName: fqtn, existingEntity: this);
}
}
}
Clean code isn't always easily readable, but the aspects/attributes will raise coder's awareness.
PS: I posted the unit test code on purpose to show you what's happening.
Short version:
Microkernel.Modify(this);
You can inject a factory which has the services injected into it.
public interface IImportFactory
{
ImportFleet CreateFleetImporter();
}
public class MyImportFactory : IImportFactory
{
private readonly IMyDependency1 _dependency1;
private readonly IMyDependency2 _dependency2;
public MyImportFactory(IMyDependency1 dependency1, IMyDependency2 dependency2)
{
_dependency1 = dependency1;
_dependency2 = dependency2;
}
public ImportFleet CreateFleetImporter()
{
return new ImportFleet(_dependency1, _dependency2);
}
}
Then inject the factory as a dependency in your Service class.
I have a few business objects that have to be used together to get a specific outcome. Take a look at the following very simplyfied example for reference.
My question is: how do I get a reference to the agent using DI in the Station class ? I mostly prefer constructor injection, but that is not possible the Station class already has a stationCode as a required item.
Any ideas ?
Usage:
var station1 = new Station("xx");
var station2 = new Station("yy");
var route = new Route(station1, station2);
var length = route.GetLength();
public class Location
{
public int Position {get; set;}
}
public interface IAgent
{
Location GetLocation(string stationCode);
}
public class Station
{
private string _stationCode;
public Station(string stationCode)
{
_stationCode = stationCode;
}
public Location GetLocation()
{
// issue here: how to get a reference to the agent instance using DI
_agent.GetLocation(_stationCode);
}
}
public class Route
{
private Station _station1;
private Station _station2;
public Route(Station station1, Station station2)
{
_station1 = station1;
_station2 = station2;
}
public int GetLength()
{
var location1 = _station1.GetLocation();
var location2 = _station2.GetLocation();
result = location2.Position - location1.Position;
return result;
}
}
Your classes seem to be having an identity crisis. When using DI, you should have just 2 types of classes to deal with - injectables and newables. Your Station class seems like a kludge because it both provides a service (has dependencies) and has state. To make your classes DI-friendly, you should design classes that only provide state to classes that only do something with the state (services).
Route
This class is injectable - that is, it should be wired from the DI container.
public interface IRoute
{
int GetLength(Station station1, Station station2);
}
public class Route : IRoute
{
private readonly IAgent _agent;
public Route(IAgent agent)
{
if (agent == null) throw new ArgumentNullException("agent");
_agent = agent;
}
public int GetLength(Station station1, Station station2)
{
var location1 = _agent.GetLocation(station1.StationCode);
var location2 = _agent.GetLocation(station2.StationCode);
result = location2.Position - location1.Position;
return result;
}
}
Station
This class is newable - that is, you should always use the new keyword to instantiate it.
public class Station
{
private string _stationCode;
public Station(string stationCode)
{
_stationCode = stationCode;
}
public string StationCode
{
get { return _stationCode; }
// Optional: provide setter here
}
}
Usage
var station1 = new Station("xx");
var station2 = new Station("yy");
// IRoute is injected where you need to make the calculation
var length = _route.GetLength(station1, station2);
Perhaps it would be better to rename Route to something more appropriate, since it does not provide a route, it calculates the route length.
Frankly, if your Station class doesn't have any other state than a single string variable, it would probably make more sense to eliminate the class and just use strings for station1 and station2. But this is mostly just a matter of personal taste.
The concept of two types of classes to deal with, injectables and newables, is a good idea. But when newables should contain only limited business logic, you are drifting away from pure object-oriented concepts. When you write code for a complex domain model, your newable business classes contain both business logic and data. That´s also the intention of the question, I assume. The Station and Route classes are simple examples that contain much more logic and data in reality.
So I would suggest to have better separation of concerns, by separating code for storage from you business logic. I see two common solutions for this.
When data is loaded in memory, a separate StationStore class is an injectable that loads stations and stores them in the context of the business domain, eg. in a static property:
public IEnumarable<Station> Station.Store { get; internal set; }
All DI code can be hidden in a business base class. It´s less disturbing to put DI dependencies there. So an agent can be resolved in the generic base class based on the template types provided.
public class Station : BusinessClass<Station, StationAgent>
{
public string StationCode { get; internal set; }
public Location Location { get; internal set; }
public Station(string stationCode)
{
base.Load(stationCode, this);
}
}
I'm in the middle of creating a new library, and as I was building it something seemed a little odd.
Here's the code:
namespace traditional_poker
{
public class poker
{
public class hand
{
public String Name
{
get; set;
}
public String[] cards
{
get; set;
}
}
List<hand> players;
public void AddPlayer(String name)
{
hand newHand = new hand();
newHand.Name = name;
players.Add(newHand);
}
}
}
I have List<hand> players inside the Library itself, which means the library is storing data (albeit temporarily).
Is this bad practice?
Is there a better way to do this?
Or is the way I'm doing it completely legitimate?
It all depends on the way you want to tackle the problem.
If you want to have the data temporarily then it is Ok, If you want to save your data between different application instances or across different sessions then you should use a data persistent tool (filing, databases, ...)
namespace traditional_poker
{
public class poker
{
public class hand // use PascalCaseNamingConvention
{
public String Name
{
get; set;
}
public String[] cards // use PascalCaseNamingConvention
{
get; set;
}
}
List<hand> players;
public void AddPlayer(String name)
{
hand newHand = new hand();
newHand.Name = name;
players.Add(newHand); //null reference exception here! you should initialize players
}
}
}
The library is not storing data.
It offers functionality, using classes, which have fields. These classes are instantiated by an application using them, in the application memory space.
If it were bad practice to have data 'stored' in libraries, then libraries would not have classes or variables, and be severely limited.
The title is a bit confusing, hopefully someone maybe know's a better fitting title for my problem.
I am trying to create a class which derives from Collection<Classname> to implement an easy way to save and loading Configuration files. Writing to file is no problem, but I am not able to implement the deserialze function. I am unsure how to assign the deserialized content back to my instance.
Current approach:
[DataContract(Name = "Configurations", Namespace = "")]
public class Configurations : Collection<Configuration>
{
internal void SerializeToBinaryFile(string path)
{
Helper.DumpObjectToBinaryFile(this, path);
}
internal void DeserializeFromBinaryFile(string path)
{
// Getting Error:
// This expression can not be used as an assignment target
this = Helper.GetObjectFromBinaryFile<Collection<Configuration>>(path);
}
}
I am familiar with this.Add([Configuration]) but this just gives the opportunity to insert one item. I thought about using a foreach(Configuration c in temporaryObject and add them one by one but this can't be the best solution.
Thanks for any hint!
Edit 1:
I've added the foreach iteration for adding the Configurations
internal void DeserializeFromBinaryFile(string path)
{
foreach (var c in Helper.GetObjectFromBinaryFile<Collection<Configuration>>(path))
{
Add(c);
}
}
This seems to work fine. Does someone know a better pattern?
You cannot assign to new instance of class to "this" regardless if you are doing de-serialization or something else. Code bellow just uses new constructor and doesn't work either. Basically, you do have different 2 instances of class in memory at that point.
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public void CreatePoint(int x, int y)
{
// Doesn't work either
this = new Point();
}
}
You have to do this outside of the body of the class, so rather make static deserialization method:
[DataContract(Name = "Configurations", Namespace = "")]
public class Configurations : Collection<Configuration>
{
internal void SerializeToBinaryFile(string path)
{
Helper.DumpObjectToBinaryFile(this, path);
}
internal static Configurations DeserializeFromBinaryFile(string path)
{
return Helper.GetObjectFromBinaryFile<Collection<Configuration>>(path);
}
}
I have a situation where I have 8 steps (think of it as a wizard). Each step consists of something different so I've created 8 classes. Each of the classes need some information from the previous steps (classes). All the classes are called from one main class. The neatiest way I've found to handle this situation is :
public void Main()
{
var step1 = new Step1();
step1.Process();
var step2 = new Step2(step1);
step2.Process();
var step3 = new Step3(step1, step2);
//...
var step8 = new Step8(step1, step2, step3, step4, step5, step6, step7);
step8.Process();
}
Obviously, this is a mess. I don't want to send that many parameters and I don't want to use static classes (probably not a good practice).
How would you handle such situation?
This sounds to me like something that you could accomplish via a Chain of Responsibility Pattern. That is the direction that I would look into at least.
If you go down that path, then you will leave yourself open to a cleaner implementation of adding/removing steps in the future.
And, as far as the multiple data sets, John Koerner is correct in that you should have one data model that is updated in each step. This will allow you to implement a clean chain of responsibility.
Have a single class that is your datamodel that can be used throughout the processes. The steps update their piece of the datamodel and that is the only object passed to each subsequent step.
Seems like Java's inner classes are better suited for this than anything C# has. But, C# is so much better in so many other aspects, we'll let this one pass.
You should create one class that contains all your data. If your steps are simple, you should have one method per step in that one class. If your steps are complicated, separate them into classes, but give each of them access to the data class.
You can have interface IProcess with method Run(Wizard) and property Name, several processes and everyone inherits IProcess, and class Wizard that contain processes to run in the list. So:
class Wizard
{
private IList<IProcess> processes = new List<IProcess();
public T GetProcess<T>(string name)
where T : IProcess
{
return (T)processes.Single(x => x.Name == name);
}
public void Run()
{
foreach (var proc in processes)
proc.Run(this);
}
}
Every process can have access to the wizard using argument of the Run method, or just have it in the constructor. By calling wizard.GetProcess<Process1>("some name") you can have your process that was previously executed (you can add a check).
Other option is to contain results in the Wizard class.
This is only one of many variants. You can look at Chain of Responsibility Pattern, like Justin suggests
I would say a classical example for a variation of a Chain-Of-Responsibility.
Here is an example:
class Request
{
private List<string> _data;
public IEnumerable<string> GetData()
{
return _data.AsReadOnly();
}
public string AddData(string value)
{
_data.Add(value);
}
}
abstract class Step
{
protected Step _nextStep;
public void SetSuccessor(Step step)
{
_nextStep = step;
}
public abstract void Process(Request request);
}
sealed class Step1 : Step
{
public override void Process(Request request)
{
var data = request.GetData();
Console.Write("Request processed by");
foreach (var datum in data)
{
Console.Write(" {0} ", datum);
}
Console.WriteLine("Now is my turn!");
request.AddData("step1");
_nextStep.Process(request);
}
}
// Other steps omitted.
sealed class Step8 : Step
{
public override void Process(Request request)
{
var data = request.GetData();
Console.Write("Request processed by");
foreach (var datum in data)
{
Console.Write(" {0} ", datum);
}
Console.WriteLine("Guess we're through, huh?");
}
}
void Main()
{
var step1 = new Step1();
// ...
var step8 = new Step8();
step8.SetSuccessor(step1);
var req = new Request();
step1.Process(req);
}
Create just one class and use different methods as steps
class Wizard
{
int someIntInfo;
string some StringInfo;
...
public void ProcessStep1();
public void ProcessStep2();
public void ProcessStep3();
public void ProcessStep4();
}
Or create a step and an info interface and declare the wizard like this by passing the same info to all steps
interface IWizardInfo
{
int someIntInfo { get set; }
string someStringInfo { get set; }
...
}
interface IStep
{
void Process(IWizardInfo info);
}
class Wizard
{
IWizardInfo _info = ....;
IStep[] _steps = new IStep[] { new Step1(), new Step2(), ... };
int _currentStep;
void ProcessCurrentStep()
{
_steps[_currentStep++].Process(_info);
}
}
EDIT:
Create a compound class which can hold all previous steps
class Step1 { public Step1(AllSteps steps) { steps.Step1 = this; } ... }
class Step2 { public Step2(AllSteps steps) { steps.Step2 = this; } ... }
class Step3 { public Step3(AllSteps steps) { steps.Step3 = this; } ... }
class AllSteps
{
public Step1 Step1 { get; set; }
public Step2 Step2 { get; set; }
public Step3 Step3 { get; set; }
}
Pass the same info to all steps. The steps are responsible to add themselves to the info
AllSteps allSteps = new AllSteps();
var stepX = new StepX(allSteps);
Why not create one single class for all of your steps and implement state management within that class? e.g.
private class Steps
{
private int _stepIndex = 0;
public void Process()
{
switch(_stepIndex)
{
case 0: // First Step
... // Perform business logic for step 1.
break;
case 1: // Second Step
... // Perform business logic for step 2.
break;
}
_stepIndex++;
}
}
I would have two ArrayLists (or depending on your class and method structure they might be simple Lists) - one for methods (as delegates) and one for results.
So, foreach method would go through delegates and invoke them with results list as parameter (you might accommodate your methods to accept such parametars and work with them) and add result to results list.