I have two classes OnlineBoolTag and OnlineDoubleTag. I add these objects to a list and want to get the Value of different types. How to return Value property of double or bool?
public class OnlineDoubleTag : IOnlineTag
{
public string Name { get; set; }
public double Value { get; set; }
}
public class OnlineBoolTag : IOnlineTag
{
public string Name { get; set; }
public bool Value { get; set; }
}
Add objects to a list:
var onlinetags = new List<IOnlineTag>();
onlinetags.Add(new OnlineBoolTag { Name = "Bool1", Value = true });
onlinetags.Add(new OnlineDoubleTag { Name = "Float1", Value = 777.22 });
foreach (var tag in onlinetags)
{
Console.WriteLine(tag.*****Value*****);
}
You can use dynamic instead of object
interface IOnlineTag
{
public dynamic GetValue();
}
public class OnlineDoubleTag : IOnlineTag
{
public string Name { get; set; }
public double Value { get; set; }
public dynamic GetValue()
{
return this.Value;
}
}
public class OnlineBoolTag : IOnlineTag
{
public string Name { get; set; }
public bool Value { get; set; }
public dynamic GetValue()
{
return this.Value;
}
}
public static void Main()
{
var onlinetags = new List<IOnlineTag>();
onlinetags.Add(new OnlineBoolTag { Name = "Bool1", Value = true });
onlinetags.Add(new OnlineDoubleTag { Name = "Float1", Value = 7777.22 });
foreach (var tag in onlinetags)
{
Console.WriteLine($"{tag.GetValue()} {tag.GetValue().GetType()}");
}
// Value: True Type: System.Boolean
// Value: 7777.22 Type: System.Double
}
Using dynamic will help here, as Guy's answer points out. We can simplify this even further though, by defining the property Value to be of type dynamic itself. This removes the need to implement the interface for GetValue method. Instead, we can do this:
public class OnlineTag
{
public string Name {get;set;}
public dynamic Value {get;set;}
}
public class Program
{
public static void Main(string[] args)
{
var onlinetags = new List<OnlineTag>();
onlinetags.Add(new OnlineTag { Name = "Bool1", Value = true });
onlinetags.Add(new OnlineTag { Name = "Float1", Value = 7777.22 });
foreach (var tag in onlinetags)
{
Console.WriteLine($"{tag.Value} {tag.Value.GetType()}");
//prints the below
//True System.Boolean
//7777,22 System.Double
}
}
}
The pitfall with this is that defining Value as dynamic allows you to reassign a value of totally different type later on in your code. For example, the below code will not throw any errors:
Console.WriteLine($"{onlinetags[0].Value} {onlinetags[0].Value is bool}"); //prints True True
onlinetags[0].Value = 123M;
Console.WriteLine($"{onlinetags[0].Value} {onlinetags[0].Value.GetType()}"); // prints 123 System.Decimal
I have a list of source classes derived from a base source class and a list with destination classes derived from a base destination class. There is only one destination class corresponding to a source class. I want to make a generic converter which updates an existing destination object, given his corresponding source object.
Updated completely:
I have the following code:
using System;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
S1 newItem = new S1()
{
Age = 11,
Name = "John"
};
D1 oldItem = new D1()
{
Age = 10
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<S1, D1> convertor = new Convertor<S1, D1>(newItem, oldItem);
S2 newItem2 = new S2()
{
City = "London",
Name = "Lynda"
};
D2 oldItem2 = new D2()
{
City = "Paris"
};
Convertor<S2, D2> convertor2 = new Convertor<S2, D2>(newItem2, oldItem2);
Console.ReadKey();
}
}
public abstract class SourceDomain
{
public string Name { get; set; }
internal abstract void SetItem<Y>(Y oldItem) where Y : DestinationDomain;
}
public class S1 : SourceDomain
{
public int Age { get; set; }
internal override void SetItem<Y>(Y oldItem)
{
Console.WriteLine("here I want to update the age of oldItem (10) with the new value (11)");
//oldItem.Age = Age;
}
}
public class S2 : SourceDomain
{
public string City { get; set; }
internal override void SetItem<Y>(Y oldItem)
{
Console.WriteLine("here I want to update the city of oldItem Paris with the new value London");
// oldItem.City = City;
}
}
public class DestinationDomain { }
public class D1 : DestinationDomain
{
public int Age { get; set; }
}
public class D2 : DestinationDomain
{
public string City { get; set; }
}
public class Convertor<X, Y> where X : SourceDomain where Y : DestinationDomain
{
protected X item;
protected Y oldItem;
public Convertor(X newObject, Y oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of item type, the proper method, not the base one.
item.SetItem(oldItem);
}
}
}
SourceDomain and DestinationDomain are base classes and there are a lot of derived classes for each of them S1, S2, D1, D2, etc.
This converter receives two classes as types and two objects of that classes and tries to update the destination item of type Y with source item of type X.
In the above example, I want to change update the age of the D1 oldItem variable with 11, and the City oldItem2 with the "London" value, but I cannot access that properties in SetItem method.
This needs to be done with a combination of inheritance and generics, and we'll make the two work together with generic type constraints.
Here are the requirements as I understand them:
You've got some data you want to copy from Source to Destination; one kind of data has an Age, one has a City, maybe another has a Poodle or a SwimmingPool. We'll define an interface that says: "This is a data object which can copy its own properties from another object of the same type", and we'll put all our data in little classes which know how to copy themselves. The "I can copy things like me" interface doesn't know what properties will be copied; it just requires the concrete class to implement a method that knows those details internally. As far as this example goes it could be a base class, but my assumption is the “copyability” isn’t the core indentity of these objects. It’s not what they represent; it’s just one thing we need to be able to do with them along the way.
The other things we need are a "source thing", and a "destination thing". A source thing just needs to provide a data object that can be copied. A destination thing just needs to receive a data object that can be copied.
You confused yourself by trying to mix up the sources and destinations with the data items. If you're going crazy trying to make your class do two contradictory things at once, try breaking it up into two classes that each does one thing.
You never do anything with your SourceDomain Name property, so I won't either. If you need to, I'll leave that as an exercise.
public interface ICopyable<T>
{
void CopyFrom(T other);
}
internal class Program
{
private static void Main(string[] args)
{
var newItem = new SourceDomain<Person>
{
Item = new Person { Age = 11 },
Name = "John"
};
var oldItem = new DestinationDomain<Person>
{
Item = new Person { Age = 10 }
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<Person> convertor = new Convertor<Person>(newItem, oldItem);
var newItem2 = new SourceDomain<Location>()
{
Item = new Location { City = "London" },
Name = "Lynda"
};
var oldItem2 = new DestinationDomain<Location>()
{
Item = new Location { City = "Paris" }
};
Convertor<Location> convertor2 = new Convertor<Location>(newItem2, oldItem2);
Console.ReadKey();
}
}
public class SourceDomain<T>
{
public string Name { get; set; }
public T Item { get; set; }
}
public class DestinationDomain<T> where T : ICopyable<T>, new()
{
public string Name { get; set; }
public T Item { get; set; }
public void CopyItemFrom(T other)
{
if (Item == null)
{
Item = new T();
}
Item.CopyFrom(other);
}
}
// A person is a thing which can turn itself into a copy of another Person.
// You could define a class Wombat : ICopyable<Locomotive>, if you wanted to be
// able to convert Locomotives to Wombats. You'd just add another CopyFrom()
// overload, public void CopyFrom(Locomotive other).
public class Person : ICopyable<Person>
{
public int Age { get; set; }
public void CopyFrom(Person other)
{
Age = other.Age;
}
}
public class Location : ICopyable<Location>
{
public String City { get; set; }
public void CopyFrom(Location other)
{
City = other.City;
}
}
public class Convertor<X> where X : ICopyable<X>, new()
{
protected SourceDomain<X> item;
protected DestinationDomain<X> oldItem;
public Convertor(SourceDomain<X> newObject, DestinationDomain<X> oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of item type, the proper method, not the base one.
//newObject.Data = oldItem.Data;
oldItem.CopyItemFrom(item.Item);
}
}
Homework:
Modify this code so DestinationDomain.CopyItemFrom() receives the source itself, not the source's item.
I think it's better the way I wrote it. Think of reasons why I might have thought that.
Seriously, find out what ref does, and never again use a keyword in your code if you are only guessing about what it might mean. Don't just throw code at the wall, hoping it sticks. You'll get yourself in a lot of frustrating trouble that way.
Finally i have done this:
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
S1 newItem = new S1()
{
Age = 11,
Name = "John"
};
D1 oldItem = new D1()
{
Age = 10
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<S1, D1> convertor = new Convertor<S1, D1>(newItem, oldItem);
S2 newItem2 = new S2()
{
City = "London",
Name = "Lynda"
};
D2 oldItem2 = new D2()
{
City = "Paris"
};
Convertor<S2, D2> convertor2 = new Convertor<S2, D2>(newItem2, oldItem2);
Console.ReadKey();
}
}
public interface ICopyable<T>
{
void CopyFrom(T other);
}
public abstract class SourceDomain
{
public string Name { get; set; }
}
public class S1 : SourceDomain
{
public int Age { get; set; }
}
public class S2 : SourceDomain
{
public string City { get; set; }
}
public class DestinationDomain { }
public class D1 : DestinationDomain, ICopyable<S1>
{
public int Age { get; set; }
public void CopyFrom(S1 other)
{
Console.WriteLine("oldItem.Age " + Age + " new Age; = " + other.Age);
Age = other.Age;
Console.WriteLine("oldItem.Age " + Age + " new Age; = " + other.Age);
}
}
public class D2 : DestinationDomain, ICopyable<S2>
{
public string City { get; set; }
public void CopyFrom(S2 other)
{
City = other.City;
Console.WriteLine(" oldItem.City = City;");
}
}
public class Convertor<X, Y> where X : SourceDomain where Y : DestinationDomain, ICopyable<X>
{
protected X item;
protected Y oldItem;
public Convertor(X newObject, Y oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of X type, the proper method, not the base one.
oldItem.CopyFrom(item);
Console.WriteLine(item);
}
}
}
Let's say I have a class StockMarket which has a list of Companies.
class StockMarket : IStock
{
private static List<IObserverPush> observersPush;
private static List<IObserverPull> observersPull;
public static List<Company> Companies { get; private set; }
public StockMarket()
{
observersPush = new List<IObserverPush>();
observersPull = new List<IObserverPull>();
Companies = new List<Company>() { new Company("Unilever", "UNA", 47.72, 0.77, 1.63, -3.45, "135B"),
new Company("ING Groep", "INGA", 13.40, -0.07, -0.50, -12.38, "60.4B"),
new Company("ArcelorMittal", "MT", 29.50, 0.14, 0.48, 36.05, "54.6B"),
new Company("ASML Holding", "ASML", 167.40, 2.00, 1.21, 36.49, "53.3B"),
new Company("Heineken", "HEIA", 87.66, -0.02, -0.02, 2.80, "49B"),
new Company("RELX", "REN", 18.15, 0.17, 0.95, -0.22, "38.9B"),
new Company("Philips", "PHIA", 35.49, 0.17, 0.47, 7.61, "33.3B"),
new Company("Unibail Rodamco", "UL", 196.40, -0.15, -0.08, -16.78, "20.3B"),
new Company("Akzo Nobel", "AKZA", 75.68, -0.16, -0.21, 0.33, "19.4B"),
new Company("Altice", "ATC", 7.58, 0.16, 2.16, -66.30, "17.6B")};
Thread thread = new Thread(SimulateMarket);
thread.Start();
}
public void Subscribe(IObserverPull o)
{
observersPull.Add(o);
o.UpdateMarket();
}
public void Unsubscribe(IObserverPull o)
{
observersPull.Remove(o);
}
public void Subscribe(IObserverPush o)
{
observersPush.Add(o);
o.UpdateMarket(Companies);
}
public void Unsubscribe(IObserverPush o)
{
observersPush.Remove(o);
}
public void NotifyObservers()
{
foreach(IObserverPush o in observersPush)
{
o.UpdateMarket(Companies);
}
foreach(IObserverPull o in observersPull)
{
o.UpdateMarket();
}
}
public void SimulateMarket()
{
while(observersPush.Count + observersPull.Count > 0)
{
//randomly change property values of companies
//and notify the observers about the changes
}
}
}
Company class has some properties.
public class Company
{
public string Name { get; private set; }
public string Symbol { get; private set; }
public double Price { get; set; }
public double Change { get; set; }
public double ChangePercentageDay { get; set; }
public double ChangePercentageYear { get; set; }
public string Capital { get; private set; }
public Company(string name, string symbol, double price, double change, double changePercentageDay,
double changePercentageYear, string capital)
{
Name = name;
Symbol = symbol;
Price = price;
Change = change;
ChangePercentageDay = changePercentageDay;
ChangePercentageYear = changePercentageYear;
Capital = capital;
}
}
The Forms have references to the StockMarket and they use it to retrieve data about the companies and to display it.
Form 1
public partial class ConcreteObserverPush : Form, IObserverPush
{
private StockMarket stockMarket;
public ConcreteObserverPush()
{
InitializeComponent();
stockMarket = new StockMarket();
stockMarket.Subscribe(this);
}
public void UpdateMarket(List<Company> companies)
{
stockMarketListView.Items.Clear();
foreach(Company c in companies)
{
ListViewItem item = new ListViewItem(c.Symbol);
item.SubItems.Add(c.Price.ToString());
item.SubItems.Add(c.Change.ToString());
item.SubItems.Add(c.ChangePercentageDay.ToString() + "%");
stockMarketListView.Items.Add(item);
}
}
private void ConcreteObserverPush_FormClosing(object sender, FormClosingEventArgs e)
{
stockMarket.Unsubscribe(this);
}
}
Form 2
public partial class ConcreteObserverPull : Form, IObserverPull
{
private StockMarket stockMarket;
public ConcreteObserverPull()
{
InitializeComponent();
stockMarket = new StockMarket();
stockMarket.Subscribe(this);
}
public void UpdateMarket()
{
stockMarketListView.Items.Clear();
foreach (Company c in StockMarket.Companies)
{
ListViewItem item = new ListViewItem(c.Symbol);
item.SubItems.Add(c.Name);
item.SubItems.Add(c.Price.ToString());
item.SubItems.Add(c.Change.ToString());
item.SubItems.Add(c.ChangePercentageDay.ToString() + "%");
item.SubItems.Add(c.ChangePercentageYear.ToString() + "%");
item.SubItems.Add(c.Capital);
stockMarketListView.Items.Add(item);
}
}
private void ConcreteObserverPull_FormClosing(object sender, FormClosingEventArgs e)
{
stockMarket.Unsubscribe(this);
}
}
The problem is that if the Form gets the list of companies through the property on StockMarket it can change their state. However, I want only StockMarket to have the ability to change the state of the company.
So what would be the best way to share Company state with Form when requested and preventing the Form from modifying it.
I know that a possible solution would be to return clones of Company objects, but I believe there should be a better solution.
Any help is appreciated!
The general gist of this would be to make your Company object immutable. Then you would add methods to the StockMarket object to manipulate the Company list and replace entries with new ones when you want to change a value.
Here's a quick example put together in LINQPad of making the Company class immutable and adding an UpdatePrice method to the StockMarket class.
Whether you want to be able to manipulate the Companies property from outside the StockMarket can be handled by returning the list as ReadOnlyCollection so that it's size can't be manipulated by a consumer.
void Main()
{
var sm = new StockMarket();
sm.Companies.Add(new Company("Test", "TST", 50, 0));
sm.UpdatePrice("Test", 45);
var testCompany = sm.Companies.First(x => x.Name == "Test");
Console.WriteLine($"{testCompany.Name},{testCompany.Symbol},{testCompany.Price},{testCompany.Change}");
//Output: Test,TST,45,-5
}
class StockMarket
{
public List<Company> Companies { get; private set; } = new List<Company>();
public void UpdatePrice(string name, double price) {
var index = Companies.FindIndex(x => x.Name == name);
if(index >= 0)
{
var previous = Companies[index];
Companies[index] = new Company(previous.Name, previous.Symbol, price, price - previous.Price);
}
}
}
class Company
{
public Company(string name, string symbol, double price, double change) {
Name = name;
Symbol = symbol;
Price = price;
Change = change;
}
public string Name { get; }
public string Symbol { get; }
public double Price { get; }
public double Change { get; }
///...
}
This would be a solution:
Create the Company class as a Private Inner Class inside of the StockMarket class, that way it'd only be accessible inside of it, and then provide an interface that only includes the get of all the properties and make Company implement it. You would have to make StockMarket's Company list to be the Interface's type.
Any modification you'd have to do you'd do it by casting the interface's List objects into the original class type.
Example:
class Program
{
public static StockMarket stockMarket = new StockMarket();
static void Main(string[] args)
{
}
}
public interface ICompany
{
string Name { get; }
}
public class StockMarket
{
public StockMarket()
{
Companies = SomeWildFunctionThatRetrievesAllCompanies();
}
public void OneWildFunctionThatModifiesACompany()
{
Company dunno = (Company)Companies[0];
dunno.Name = "Modification Made Possible";
}
private List<ICompany> SomeWildFunctionThatRetrievesAllCompanies()
{
return new List<ICompany>(new List<Company>());
}
public List<ICompany> Companies { get; private set; }
private class Company : ICompany
{
public string Name { get; set; }
}
}
Try this:
class Company
{
public Company(Type type,string name,string symbol,double price, double change)
{
if (type.Name == "StockMarket")
{
Name = name;
Symbol = symbol;
Price = price;
Change = change;
}
}
private string Name { get; set; }
private string Symbol { get; set; }
private double Price { get; set; }
private double Change { get; set; }
///...
}
This will allow you to change the state only if the type is StockMarket
like:
class StockMarket
{
public List<Company> Companies { get; set; }
public StockMarket()
{
Companies = new List<Company>();
}
public StockMarket someMethod()
{
//You can change the state here
StockMarket s = new StockMarket();
s.Companies.Add(new Company(this.GetType(), "aa", "_", 123, 1234));
return s;
}
//...
}
Now you cannot change the state here:
public partial class Observer: Form
{
private StockMarket stockMarket;
public ConcreteObserverPull()
{
InitializeComponent();
stockMarket = new StockMarket();
//Here you cannot change the state
stockMarket.Companies.Add(new Company(this.GetType(), "aa", "_", 123,12));
}
//...
}
Sorry, I don't know C#, but as an idea, you can wrap returned entities with decorator or proxy, which will throw an exception in case of trying to modify state of a company.
Returning clones with fields set as readonly is the safest way to go.
I want to call a method for my WPF-App with subtype objects of my Piece class. My problem is that the subtype objects have more properties than e.g the the Text objects.
Do you know a way to cope with this better than I do in my FillForm example?
namespace Namespace
{
public abstract class Piece
{
public int id { get; set; }
public string title { get; set; }
public string description { get; set; }
}
public class Text : Piece
{
}
public class Image: Piece{
public string filePath { get; set; }
public string fileformat { get; set; }
}
public class Video : Image
{
}
}
}
Example method:
public void FillForm(Piece currentPiece)
{
pieceIdTextBox.Text = currentPiece.id.ToString();
pieceNameTextBox.Text = currentPiece.title;
pieceDescriptionTextBox.Text = currentPiece.description;
if (!currentPiece.GetType().ToString().Equals("Namespace.Text"))
{
pieceFileSelectURLTextBlock.Text = (currentPiece as Namespace.Image).filePath;
SetPreviews((currentPiece as Namespace.Image).filePath);
}
}
Thanks!
Why not just change the method to the following with more type-safety
public void FillForm(Piece currentPiece)
{
pieceIdTextBox.Text = currentPiece.id.ToString();
pieceNameTextBox.Text = currentPiece.title;
pieceDescriptionTextBox.Text = currentPiece.description;
if (currentPiece as Namespace.Image imagePiece)
{
pieceFileSelectURLTextBlock.Text = imagePiece.filePath;
SetPreviews(imagePiece.filePath);
}
}
Do a safecast:
public void FillForm(Piece currentPiece)
{
pieceIdTextBox.Text = currentPiece.id.ToString();
pieceNameTextBox.Text = currentPiece.title;
pieceDescriptionTextBox.Text = currentPiece.description;
var imagePiece = currentPiece as Image;
if(imagePiece != null)
pieceFileSelectURLTextBlock.Text = imagePiece .filePath;
SetPreviews(imagePiece .filePath);
}
}
What should I be calling the "BFactory" below. Its not really a Factory since there is no selection of a concrete class happening, and its not necessarily creating an object each time. Its kind of a Pool but the users do not return the Bs they get to the pool after they are done with them. It could be called a Cache but performance is not the primary intention. The intention is that everyone who is using the same BFactory will get the same B when they pass the same A which starts to sound kind of like a singleton-ish.
public class A
{
public int MyProperty { get; set; }
}
public class B
{
public B(A wrapped)
{
Wrapped = wrapped;
}
public A Wrapped { get; set; }
}
public class BFactory
{
private Dictionary<A,B> _created = new Dictionary<A,B>();
public B GetB(A a)
{
if (_created.ContainsKey(a) == false)
{
_created[a] = new B(a);
}
return _created[a];
}
}
here is a slightly more real example:
The value from MyModel is shown in several locations in the app by binding a TextBlock to the ValueString property of MyViewModel. The user can select to present the value as a percent or a decimal and it should be updated in all locations if it is updated in one.
public class MyModel
{
public int Value { get; set; }
}
public class MyViewModel
{
private readonly MyModel _model;
public MyViewModel(MyModel model)
{
_model = model;
}
public string ValueString
{
get { return string.Format(FormatString, _model.Value); }
}
public string FormatString { get; set; }
}
public class MyViewModelFactory
{
private readonly Dictionary<MyModel, MyViewModel> _created = new Dictionary<MyModel, MyViewModel>();
public MyViewModel GetViewModel(MyModel model)
{
if (_created.ContainsKey(model) == false)
{
_created[model] = new MyViewModel(model);
}
return _created[model];
}
}