Save actions or funcs on secondary memory - c#

I am creating a program where the user creates custom commands and execute them when needed. as a result I have a class similar to:
public class Command
{
Action c { get; set; }
// Overloaded Constructors------------------------------------
// changes the volume
public Command(int volumeChange)
{
c = ()=>
SomeClass.ChangeMasterVolume(volumeChange);
}
// Animate something
public Command(int x, int y)
{
c = ()=>
SomeClass.MoveMouse(x,y);
}
// etc.. there are more contructors....
//---------------------------------------------------------
public void ExecuteCommand()
{
c();
}
}
When the user closes the application I will like to save those commands somewhere on disk. There are about 200 different commands and it will be nice if I could serialize an instance from that class. Since it contains an Action it is not possible to serialize it.
It will be nice if I don't have to create a huge switch statement in order to determine what command to execute. What is the best way of dealing with this?

Sounds to me like you simply need to keep an interface around instead of a delegate.
public interface IDoThingy
{
void DoStuff();
}
public class IncreaseVolumeThingy : IDoThingy
{
public int Volume { get; set; }
public IncreaseVolumeThingy(int volume)
{
Volume = volume;
}
public void DoStuff()
{
SomeClass.ChangeMasterVolume(Volume);
}
}
public class Command
{
protected IDoThingy _thingy = null;
public Command(IDoThingy thingy)
{
_thingy = thingy;
}
public void ExecuteCommand()
{
_thingy.DoStuff();
}
}
So instead of creating a set of constructors, you simply make some form of factory based on the command specified. If the user is setting up a Increase volume command, then you new an instance of the IncreaseVolumeThingy and store it. When it is serialized, it can be recreated from state without a delegate.

Use reflection to call a class method by its name. Serialize the class and method name.
http://www.codeproject.com/Articles/19911/Dynamically-Invoke-A-Method-Given-Strings-with-Met

Related

How to create a class with a customizable codeblock?

I am currently trying to make a console for my game, and decided making a class called Command which can then be used to create commands easily was a good idea. I made the class but of course these classes are going to do vastly different thing, as such I was thinking of making a property which would basically act like a function, aka I could construct a command with properties commandName, arguments and then the customizable code block which would then be executed upon writing the command. How would I go about this?
public class Command : MonoBehaviour
{
string inputCommand;
int arguments;
void execution()
{
//this is where to codeblock to be executed upon typing the command would go
}
}
Edit:
I made what seems to be progress but still can't seem to get it right. Also each action needs to be able to have different amounts of arguments (for example "runes.add" needs an integer for runes to add and "updatestore" needs none). Any help would be greatly appreciated
public class Command : MonoBehaviour
{
public string InputCommand { get; set; }
public int Arguments { get; set; }
public Action ExecuteAction { get; set; }
}
public class Commands
{
public List<Command> commandCollection = new List<Command>()
{
new Command()
{
InputCommand = "",
Arguments = 1,
ExecuteAction = new Action(()=>{code to execute goes here})
}
};
}
First of all, you shouldn't derive Command from MonoBehaviour if you want to construct Command with object constructor (not Instantiate).
I think you should make abstract Command class and create commands as classes derived from Command class.
Also what you call "code block" can be done using polymorphism.
So, what you need to do:
Create Command class
public abstract class Command
{
public abstract void Execute(string[] args);
}
Execute method is abstract so we can override realisation of this method in subclasses. This methods takes an array of command arguments as the parameter.
Create some test commands
public class TestCommand : Command
{
public override void Execute(string[] args)
{
Debug.Log("Test command invoked, passed parameters count: " + args.Length);
}
}
Create CommandRegistry class (it's your Commands class)
public class CommandRegistry
{
private Dictionary<string, Command> _commands;
public CommandRegistry()
{
_commands = new Dictionary<string, Command>();
}
public void RegisterCommand(string name, Command command)
{
// You should also check here if command already exists
if(_commands.ContainsKey(name))
{
// Print error here or throw an exception
return;
}
_commands[name] = command;
}
public void RegisterAllCommands()
{
// Add here every new command to register it
RegisterCommand("test", new TestCommand());
}
// Returns false if command not found
public bool ExecuteCommand(string commandName, string[] args)
{
if(_commands.ContainsKey(commandName) == false)
return false;
_commands[commandName].Execute(args);
return true;
}
}
That's it. You need to call ExecuteCommand method to execute a command and pass a name and arguments of the command.
You should check argument count inside a Command.Execute method.
Also if you need to access your game methods/fields (for example to add runes) you should provide static access to this fields/methods or create something like CommandContext class (or GameContext).
An instance of this class will be passed to every command and it contains references to objects that can do things like adding runes.
Then you will need to add a new parameter (CommandContext) to GameRegistry.ExecuteCommand and Command.Execute method.

Setting action from function parameter is null

I have some actions in a view.
public class AView
{
public Action Show { get; set; }
public Action Hide { get; set; }
}
and I'm trying to set those actions inside another class, by passing them as a parameter (I don't want to pass the whole class)
_reloader.SetupActions(Show, Hide);
Reloader is abstract, because there might be different ways of handling how Hide/Show must behave depending on the scenario we're in.
public abstract class Reloader : IReloader
{
public void SetupActions(Action show, Action hide)
{
show = Show;
hide = Hide;
}
protected virtual void Show() { ... } //what should be done when Show is invoked
protected virtual void Hide() { ... } //same for Hiding
}
And for the current view, I might be using a RapidReloader, SafeReloader, etc. This bit is irrelevant, except that the injected reloader is specific to the current view.
Now my problem is simple and logic : when I'm in SetupActions, all parameters are null (because Actions haven't been set), and setting Show into null obviously does not work.
What can I do so that when Show.Invoke() happens my view, the ShowCode from the relevant reloader is called? I would like to avoid passing the whole view as a parameter.
Also, if you have a better design, I'm all ears. We might be in an XY problem situation
You will need to use System.ValueTuple nuget package if you don't use .Net Framework 4.7 or newer.
public interface IReloader
{
(Action Show, Action Hide) GetActions();
}
public abstract class Reloader : IReloader
{
public (Action Show, Action Hide) GetActions()
{
return (Show, Hide);
}
protected virtual void Show() { }
protected virtual void Hide() { }
}
public class FastReloader : Reloader { }
public class AView
{
public Action Show{ get; set; }
public Action Hide{ get; set; }
public void IwantTheNewActions()
{
var reloader = new FastReloader();
var actions = reloader.GetActions();
Show = actions.Show;
Hide = actions.Hide;
}
}

Creating and initialize a class inside another class (nested) C#

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.

Using IObservable<T> to keep track of current state

Suppose I have an object that observes an IObservable so that it's always aware of the current state of some external source. Internally my object has a method that uses that external value as part of the operation:
public class MyObject
{
public MyObject(IObservable<T> externalSource) { ... }
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
What's the idomatic 'reactive' way of using IObservable for 'tracking current state' instead of 'responding to stream of events'.
Idea #1 is to just monitor the observable and write down values as they come in.
public class MyObject
{
private T CurrentT;
public MyObject(IObservable<T> externalSource)
{
externalSource.Subscribe((t) => { CurrentT = t; });
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
And that's fine, but keeping track of the state in a class member seems very un-reactive-y.
Idea #2 is to use a BehaviorSubject
public class MyObject
{
private readonly BehaviorSubject<T> bs;
public MyObject(BehvaiorSubject<T> externalSource)
{
this.bs = externalSource
}
public void DoSomething()
{
DoSomethingWith(bs.Value);
}
}
But using subjects directly seems to be frowned upon. But at least in this case I have the ability to use a readonly field to store the behaviorsubject.
The BehaviorSubject (or ReplaySubject) does seem like it was made for this purpose, but is there some other better way here? And if I should use the subject, would it make more sense to take the subject as an injected parameter, or take the original observable and build the subject locally in the constructor?
(by the way I'm aware about the need to deal with the 1st value if the source observable hasn't fired yet. Don't get hung up on that, that's not what I'm asking about)
I'd go with a generic solution utilizing the ReactiveUI library. RUI has a standard way of mapping IObservable<T> to an INotifyPropertyChanged stateful property.
public class ObservableToINPCObject<T> : ReactiveObject, IDisposable
{
ObservableAsPropertyHelper<T> _ValueHelper;
public T Value {
get { return _ValueHelper.Value; }
}
public ObservableToINPCObject(IObservable<T> source, T initial = default(T))
{
_ValueHelper = source.ToProperty(this, p=>p.Value, initial);
}
public Dispose(){
_ValueHelper.Dispose();
}
}
ValueHelper is contains both the current state of the observable and automatically triggers the correct INPC notification when the state changes. That's quite a bit of boiler plate handled for you.
and an extension method
public static class ObservableToINPCObject {
public static ObservableToINPCObject<T> ToINPC<T>
( this IObservable<T> source, T init = default(T) )
{
return new ObservableToINPCObject(source, init);
}
}
now given an
IObservable<int> observable;
you can do
var obj = observable.ToINPC(10);
and to get the latest value
Console.WriteLine(obj.Value);
also given that Value is an INPC supporting property you can use it in databinding. I use ToProperty all the time for exposing my observables as properties for WPF databinding.
To be Rx-ish I'd suggest avoiding the second option and go with your first, but modified in one of two ways.
Either (1) make your class disposable so that you can cleanly close off the subscription to the observables or (2) make a method that lets you clean up individual observables.
(1)
public class MyObject : IDisposable
{
private T CurrentT;
private IDisposable Subscription;
public MyObject(IObservable<T> externalSource)
{
Subscription = externalSource
.Subscribe((t) => { CurrentT = t; });
}
public void Dispose()
{
Subscription.Dispose();
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
(2)
public class MyObject
{
private T CurrentT;
public IDisposable Observe(IObservable<T> externalSource)
{
return externalSource
.Subscribe((t) => { CurrentT = t; });
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
Both allow proper clean-up and both don't use a subject.

Return an opaque object to the caller without violating type-safety

I have a method which should return a snapshot of the current state, and another method which restores that state.
public class MachineModel
{
public Snapshot CurrentSnapshot { get; }
public void RestoreSnapshot (Snapshot saved) { /* etc */ };
}
The state Snapshot class should be completely opaque to the caller--no visible methods or properties--but its properties have to be visible within the MachineModel class. I could obviously do this by downcasting, i.e. have CurrentSnapshot return an object, and have RestoreSnapshot accept an object argument which it casts back to a Snapshot.
But forced casting like that makes me feel dirty. What's the best alternate design that allows me to be both type-safe and opaque?
Update with solution:
I wound up doing a combination of the accepted answer and the suggestion about interfaces. The Snapshot class was made a public abstract class, with a private implementation inside MachineModel:
public class MachineModel
{
public abstract class Snapshot
{
protected internal Snapshot() {}
abstract internal void Restore(MachineModel model);
}
private class SnapshotImpl : Snapshot
{
/* etc */
}
public void Restore(Snapshot state)
{
state.Restore(this);
}
}
Because the constructor and methods of Snapshot are internal, callers from outside the assembly see it as a completely opaque and cannot inherit from it. Callers within the assembly could call Snapshot.Restore rather than MachineModel.Restore, but that's not a big problem. Furthermore, in practice you could never implement Snapshot.Restore without access to MachineModel's private members, which should dissuade people from trying to do so.
Can MachineModel and Snapshot be in the same assembly, and callers in a different assembly? If so, Snapshot could be a public class but with entirely internal members.
I could obviously do this by
downcasting, i.e. have CurrentSnapshot
return an object, and have
RestoreSnapshot accept an object
argument which it casts back to a
Snapshot.
The problem is that somebody could then pass an instance of an object which is not Snapshot.
If you introduce an interface ISnapshot which exposes no methods, and only one implementation exists, you can almost ensure type-safety at the price of a downcast.
I say almost, because you can not completely prevent somebody from creating another implementation of ISnapshot and pass it, which would break. But I feel like that should provide the desired level of information hiding.
You could reverse the dependency and make Snapshot a child (nested class) of MachineModel. Then Snapshot only has a public (or internal) Restore() method which takes as a parameter an instance of MachineModel. Because Snapshot is defined as a child of MachineModel, it can see MachineModel's private fields.
To restore the state, you have two options in the example below. You can call Snapshot.RestoreState(MachineModel) or MachineModel.Restore(Snapshot)*.
public class MachineModel
{
public class Snapshot
{
int _mmPrivateField;
public Snapshot(MachineModel mm)
{
// get mm's state
_mmPrivateField = mm._privateField;
}
public void RestoreState(MachineModel mm)
{
// restore mm's state
mm._privateField = _mmPrivateField;
}
}
int _privateField;
public Snapshot CurrentSnapshot
{
get { return new Snapshot(this); }
}
public void RestoreState(Snapshot ss)
{
ss.Restore(this);
}
}
Example:
MachineModel mm1 = new MachineModel();
MachineModel.Snapshot ss = mm1.CurrentSnapshot;
MachineModel mm2 = new MachineModel();
mm2.RestoreState(ss);
* It would be neater to have Snapshot.RestoreState() as internal and put all callers outside the assembly, so the only way to do a restore is via MachineModel.RestoreState(). But you mentioned on Jon's answer that there will be callers inside the same assembly, so there isn't much point.
This is an old question, but i was looking for something very similar and I ended up here and between the information reported here and some other I came up with this solution, maybe is a little overkill, but this way the state object is fully opaque, even at the assembly level
class Program
{
static void Main(string[] args)
{
DoSomething l_Class = new DoSomething();
Console.WriteLine("Seed: {0}", l_Class.Seed);
Console.WriteLine("Saving State");
DoSomething.SomeState l_State = l_Class.Save_State();
l_Class.Regen_Seed();
Console.WriteLine("Regenerated Seed: {0}", l_Class.Seed);
Console.WriteLine("Restoring State");
l_Class.Restore_State(l_State);
Console.WriteLine("Restored Seed: {0}", l_Class.Seed);
Console.ReadKey();
}
}
class DoSomething
{
static Func<DoSomething, SomeState> g_SomeState_Ctor;
static DoSomething()
{
Type type = typeof(SomeState);
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);
}
Random c_Rand = new Random();
public DoSomething()
{
Seed = c_Rand.Next();
}
public SomeState Save_State()
{
return g_SomeState_Ctor(this);
}
public void Restore_State(SomeState f_State)
{
((ISomeState)f_State).Restore_State(this);
}
public void Regen_Seed()
{
Seed = c_Rand.Next();
}
public int Seed { get; private set; }
public class SomeState : ISomeState
{
static SomeState()
{
g_SomeState_Ctor = (DoSomething f_Source) => { return new SomeState(f_Source); };
}
private SomeState(DoSomething f_Source) { Seed = f_Source.Seed; }
void ISomeState.Restore_State(DoSomething f_Source)
{
f_Source.Seed = Seed;
}
int Seed { get; set; }
}
private interface ISomeState
{
void Restore_State(DoSomething f_Source);
}
}

Categories