Currently I'm writing a wizard (using MBG SimpleWizard library). I have several pages. and as a way of sharing data between them, they are passed a class out DBManip DBController. I need to use this DBController in a method, but the call is handled by the library and so I can't easily pass DBController by reference to the method. How can I make the passed reference into a property that the method can modify, and preserve the reference.
Class Initialization:
WizardHost host = new WizardHost();
using (host)
{
host.Text = Migration.Properties.Resources.AppName;
host.ShowFirstButton = false;
host.ShowLastButton = false;
host.WizardCompleted += new WizardHost.WizardCompletedEventHandler(this.Host_WizardCompleted);
DBManip DBController;
host.WizardPages.Add(1, new Page1());
host.WizardPages.Add(2, new Page2(out DBController));
host.WizardPages.Add(3, new Page3(out DBController));
host.WizardPages.Add(4, new Page4(out DBController));
host.LoadWizard();
host.ShowDialog();
}
Constructor:
public Page2(out DBManip DBController)
{
this.InitializeComponent();
this.label1.Text = Migration.Properties.Resources.ExportDirectoryMessage;
this.exportDirTextbox.Text = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
Method:
private bool SetExportDirectory ()
{
string exportDirectory = this.exportDirTextbox.Text;
// If a path is given, check if it's valid
// and set the pathExists boolean
if (!Directory.Exists(exportDirectory))
{
MessageBox.Show(Migration.Properties.Resources.InvalidPath);
return false;
}
// Initializing the object to manipulate the databases
exportDirectory = new DBManip(exportDirectory);
return true;
}
Property which will call method:
public bool PageValid
{
get { return SetExportDirectory(); }
}
Sorry if I'm missing something simple, I'm fairly new to C#
It's not clear what your pages are doing with DBManip, but you'll need to have it as a property of any Page class that uses it.
To do that, you'd ordinarily create an instance of DBManip first before creating the pages, and pass it to each constructor that wants it. Each of those classes will have a property where it stores the reference so it can use it later. Each class will need to declare that property for itself, since you're not easily going to be able to give them a common base class of your own.
But you're creating it later. Since you need the different classes to share a reference to an object that's created after their constructors exit, we'll add a quickie "reference" generic class, and they'll all share a reference to that. Then we can change its properties, and they'll all have the new property values on the existing instance of this little "handle" class.
Reference.cs
// Semantically, this is basically a pointer to a pointer, without the asterisks.
public class Reference<T>
{
public Reference() { }
public Reference(T t) { Value = t; }
public T Value;
}
Main C#
WizardHost host = new WizardHost();
using (host)
{
host.Text = Migration.Properties.Resources.AppName;
host.ShowFirstButton = false;
host.ShowLastButton = false;
host.WizardCompleted += new WizardHost.WizardCompletedEventHandler(this.Host_WizardCompleted);
// ************************
// Create shared "reference" instance
// ************************
Reference<DBManip> dbControllerRef = new Reference<DBManip>();
host.WizardPages.Add(1, new Page1());
host.WizardPages.Add(2, new Page2(dbControllerRef));
host.WizardPages.Add(3, new Page3(dbControllerRef));
host.WizardPages.Add(4, new Page4(dbControllerRef));
host.LoadWizard();
host.ShowDialog();
}
Page2.cs
// It's not an out parameter so don't make it one.
public Page2(Reference<DBManip> dbControllerRef)
{
this.InitializeComponent();
this.DBControllerRef = dbControllerRef;
this.label1.Text =
Migration.Properties.Resources.ExportDirectoryMessage;
this.exportDirTextbox.Text =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
public Reference<DBManip> DBControllerRef {
get; private set;
}
private bool SetExportDirectory ()
{
string exportDirectory = this.exportDirTextbox.Text;
// If a path is given, check if it's valid
// and set the pathExists boolean
if (!Directory.Exists(exportDirectory))
{
MessageBox.Show(Migration.Properties.Resources.InvalidPath);
return false;
}
// Everybody has the same Refernece<DBManip>
this.DBControllerRef.Value = new DBManip(exportDirectory);
return true;
}
Related
I have a following method in my command handler that gets variables from another method,im trying to pass those variable into the CreateUser(NewAccount); method but it always comes back as null
public async Task ExecuteAsync(CreateUserAccountCommand command)
{
var result = await _client.CreateUser(GetAccountFrom(command)); // so this line gets the variables from GetAccountFrom(command)
_httpContextAccessor.HttpContext.Items["CreateUserAccountCommand"] = result;
}
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var NewAccount = new Account();
NewAccount.FirstName = command.FirstName;
NewAccount.LastName = command.LastName;
return NewAccount()
}
however when i call CreateUser to pass in the variables into NewAccount thats coming from GetAccountFrom(command) it passes it in as a null
public System.Threading.Tasks.Task<Account> CreateUser(Account NewAccount,)
{
return base.Channel.CreateUser(NewAccount);
}
What am i doing wrong?
You are creating a new instance of NewAccount in your return statement.
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var newAccount = new Account();
newAccount.FirstName = command.FirstName;
newAccount.LastName = command.LastName;
return newAccount; // <- Return the variable
}
You are creating object with new keyword. All you need to do is to return this object from your method with simple call:
return NewAccount;
The way you do it now is that you are returning result of NewAccount() method (whatever it is, apparently null), which is not what you want.
Also you might want to inspect why NewAccount() returns always null.
Your code has many anti patterns but it seems like you have a method somewhere in the base newAccount(); This is why inheritance should be avoided (for beginners and mids)
also the convention for private local variables lowercase.. as to NOT CONFUSE yourself.
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var newAccount = new Account();
newAccount.FirstName = command.FirstName;
newAccount.LastName = command.LastName;
return newAccount;
}
or to completely avoid confusion just do this
private Account GetAccountFrom(CreateUserAccountCommand command)
{
return new Account{
FirstName = command.FirstName,
LastName = command.LastName,
}
}
But to avoid anti-patterns and spaghetti code you should really make an extension method which is much more S.O.L.I.D !
namespace you.company
{
public static CommandExtensions{
public static Account GetAccountFrom(this CreateUserAccountCommand command)
{
return new Account
{
FirstName = command.FirstName,
LastName = command.LastName,
};
}
}
I am trying to create a Class Method which can be called to Query the Database. The function itself works but for some reason, when the Array is returned, they're not set.
My function code is:
public Configuration[] tbl_bus(string type, string match)
{
// Create Obejct Instance
var db = new rkdb_07022016Entities2();
// Create List
List<Configuration> ConfigurationList = new List<Configuration>();
// Allow Query
if (type.ToLower() == "bustype")
{
foreach (var toCheck in db.tblbus_business.Where(b => b.BusType == match))
{
// Create Class Instance
var model = new Configuration { Name = toCheck.Name, BusinessID = toCheck.BusinessID };
// Append to the property
ConfigurationList.Add(model);
}
}
else if (type.ToLower() == "businessid")
{
foreach (var toCheck in db.tblbus_business.Where(b => b.BusinessID == match))
{
// Create Class Instance
var model = new Configuration { Name = toCheck.Name, BusinessID = toCheck.BusinessID };
// Append to the property
ConfigurationList.Add(model);
}
}
return ConfigurationList.ToArray();
}
And my Configuration code is:
public class Configuration
{
// Properties of the Database
public string Name { get; set; }
public string BusinessID { get; set; }
public string Address { get; set; }
}
public Configuration Config { get; set; }
public Controller()
{
this.Config = new Configuration();
}
On my Handler I am doing:
// Inside the NameSpace area
Controller ctrl;
// Inside the Main Void
ctrl = new Controller();
ctrl.tbl_bus("bustype", "CUS");
context.Response.Write(ctrl.Config.Name);
I tried watching the Class function and it does create the Array, only, when I watch the ctrl.Config.Name it is always set to NULL. Could anyone possibly help me in understanding why the return isn't actually setting the properties inside the Configuration class?
Edit: The function does run and it fetches 3006 rows of Data when matching the bus_type to customer. (Its a large Database) - Only, the properties are never set on return.
Edit: Is there a specific way to return an Array to a Class to set the Properties?
Thanks in advance!
Change your Configs in Controller to array
public Configuration[] Configs { get; set; }
Change your tbl_bus function to void, and set the Configs inside the function.
public void tbl_bus(string type, string match)
{
// do your code
// set the configs here
Configs = ConfigurationList.ToArray();
}
Hope it helps.
Although this is not a complete answer to your question, the problem probably lies in the fact that you're not doing anything with the array returned by the method. You're simply discarding it right away. If you change your code to
ctrl = new Controller();
Configuration[] config = ctrl.tbl_bus("bustype", "CUS");
you will be able to reference the array later on.
Console.WriteLine(config.Length);
Now you can use it to set any properties you like.
Dearest fellow programmers,
I seem to lack some understanding as of how the referencing works in C#.
The case:
I tried to implement some sort of Memento proxy which would wrap an interface and store every parameter that we're provided to the method calls and store these into a list.
Whenever necessary we could call the RestoreState and the objects would "reset" to the original state.
The code:
Consumer and model object
class Program
{
static void Main(string[] args)
{
IMemento memento = new Memento();
PrestationInfo prestationInfo2 = new PrestationInfo { Advance = 2 };
memento.Add(prestationInfo2);
Console.WriteLine(prestationInfo2.Advance); //Expect 2
prestationInfo2.Advance = 1;
Console.WriteLine(prestationInfo2.Advance); //Expect 1
memento.RestoreState();
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Console.ReadKey();
}
}
[Serializable]
public class PrestationInfo
{
public int Advance { get; set; }
}
Memento
public interface IMemento
{
void Add(object pItem);
void RestoreState();
}
public class Memento : IMemento
{
public Memento()
{
MementoList = new Dictionary<long, object>();
ReferenceList = new List<object>();
ObjectIDGenerator = new ObjectIDGenerator();
}
private ObjectIDGenerator ObjectIDGenerator { get; set; }
private Dictionary<long, object> MementoList { get; set; }
private List<object> ReferenceList { get; set; }
public void Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
}
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
private static TCopy DeepCopy<TCopy>(TCopy pObjectToCopy)
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, pObjectToCopy);
memoryStream.Position = 0;
return (TCopy)binaryFormatter.Deserialize(memoryStream);
}
}
}
Extra info
My guess is, I'm doing/understand something wrong regarding the List.
I also tried the Interlocked.Exchange, playing around with "ref"'s, using WeakReference's and storing the object into a CareTaker object (and storing that CareTaker into the List), implement some copy Property thing...
And ... I just can't see it.
My expected result would be the PrestationInfo.Advance property containing the value 2. But it keeps
Try this:
Change the Add method:
public long Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
return id; // i need my memento! LOL
}
You should also add this accessor method:
public object GetRestoredState(long id)
{
return MementoList[id]; // you should put some range check here
}
Now that you have your id, you can fetch the restored state this way:
memento.RestoreState();
prestationInfo2 = memento.GetRestoredState(savedId); // <-- you got this when you called the Add()...
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Follow ups: you can also make the IMemento into a IMemento<T>, and adjust your code accordingly
Memento.Add needs a ref parameter modifier to access the original reference type pointer.
https://msdn.microsoft.com/en-us/library/14akc2c7.aspx?f=255&MSPPError=-2147217396
It looks like the problem is in your understanding of references in .NET
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
The RestoreState method above does not return anything, and you're strictly operating on references, not their internal state. Inside your method object reference is a local reference. It is not the same as the external prestationInfo2 and your method simply makes reference point (refer) to the previously saved copy of the state of presentationInfo2.
You could modify it something like this:
public object RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
return reference;
}
}
return null;
}
And then call it like this:
presentationInfo2 = memento.RestoreState();
If you want the memento to track objects and magically restore their state you will have to make the objects themselves aware of the memento which introduces coupling or use reflection to modify the tracked references internal state. Basically you don't deserialize the persisted state into a new object but use reflection to overwrite the previously stored internal state into the tracked object reference.
Be careful though to store references using WeakReference otherwise you will find yourself with a nice case of memory leak.
I'm making a graphic control class Info which should display some text on screen. The text is some object's string. I'd like to be able to get that object's latest value from within an instance of Info class.
class Info
{
public string Text;
}
void Program()
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info();
wind1.Text = obj.name; // this just copies current value, but should be a reference or something
/* obj.name value changes several times before it's time to display it again */
// Info window drawing method
foreach (var item in Windows) // Windows is List<Info>
Draw(item.Text); // this doesn't get the latest value
}
How should I change the code so I can get the latest string value from within the drawing section?
Update: If you need something that'll work for any type, you'll have to use delegates. For example:
class Info
{
private Func<string> getText;
public Info(Func<string> getText)
{
getText = getText;
}
public string Text
{
get
{
return getText();
}
}
}
void Program
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info(() => obj.name);
// Now do your stuff.
}
In this case, Info is given an anonymous function that returns a string. When you access its Text property, the function is evaluated to retrieve that string. How the string is retrieved, and where it comes from, is determined by the client code (i.e. the Program method). This way, Info doesn't rely on any particular type.
You could pass the ClassA object into your Info instance, so that it can get the value of.name itself.
Something like this, perhaps?
class Info
{
public Info(ClassA obj)
{
TheObject = obj;
}
public ClassA TheObject
{
get;
set;
}
public string Text
{
get
{
return TheObject.name;
}
}
}
void Program
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info(obj);
// Now do your stuff.
}
I have a Class X wich uses a Class Y. The X creates the Y, but X must create Y with THE SAME constructor method was used to create instance-Y passed to X.
It is not a Clone, because I want a NEW object-Y not equals to values of instance-Y passed to X.
It is not a instance because I do not want the SAME object-Y what is pased as instance-Y to X.
I would like to pass the "constructor method and parameters" of class Y to class X and, with this information, create the new Y-instance using the ctor-method-passed.
And I don't want to devel all 'Class Y' constructor logic because, in this case both of them will be very highly coupled.
I have done a little spike to explain myself a bit better.
Thanks.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TheSon son1 = new TheSon();
son1.TheValue = "Another Value";
TheFather<TheSon> father1 = new TheFather<TheSon>(son1);
Console.WriteLine("Result is {0}:", "Empty constructor".Equals(father1.MySon.TheValue));
Console.WriteLine("\tbecause prop. must be: '{0}' and it is: '{1}'", "Empty constructor", father1.MySon.TheValue);
}
public class TheFather<T> where T: TheSon
{
public TheSon MySon { get; set; }
public TheFather(T mySon) {
// I would like to NOT use the same object but
// use the constructor that was used to build the passed object-instance.
//
// Or perhaps pass a concrete TheSon constructor to the 'TheFather'...
this.MySon = (TheSon)mySon;
}
}
public class TheSon
{
public string TheValue { get; set; }
public TheSon()
{
this.TheValue = "Empty constructor";
}
public TheSon(string value)
{
this.TheValue = value;
}
public TheSon(string value, int element)
{
this.TheValue = value + "-> " + Convert.ToString(element);
}
}
}
}
=========SOLUTION:
Adding this constructor to the TheFather class:
public TheFather(Func<T> sonFactory)
{
this.MySon = (T)sonFactory();
}
And with this example:
static void Main(string[] args)
{
// Uncomment one of this to change behaviour....
//Func<TheSon> factory = () => new TheSon();
Func<TheSon> factory = () => new TheSon("AValue");
//Func<TheSon> factory = () => new TheSon("AValue", 1);
TheFather<TheSon> father1 = new TheFather<TheSon>(factory);
Console.WriteLine("Result is {0}:", "AValue".Equals(father1.MySon.TheValue));
Console.WriteLine("\tbecause prop. must be: '{0}' and it is: '{1}'", "AValue", father1.MySon.TheValue);
}
Works like a charm.... :-)
Thanks...
You can simply use a factory to create TheSon objects:
Func<TheSon> factory = () => new TheSon(); // creates one with default ctor
This way you can get a new object each time, but created in exactly the same way (this is not limited to a constructor; you can also include any additional code you want). Use it like this:
var oneSon = factory(); // creates one son
var secondSon = factory(); // creates another with the same constructor
var father = new TheFather(factory()); // ditto
Update: You can also change TheFather's constructor to accept a factory if you want to create TheSon inside TheFather. For example:
public TheFather(Func<T> sonFactory) {
this.MySon = (TheSon)sonFactory();
}
and
var father = new TheFather(factory);