Reputation: 177
I think I'm experiencing a basic OOP misunderstanding here:
(These are Entity Framework 6 classes btw, in case you're surprised by the "virtual")
public class WeaponUsed : HistoryEvent
{
public virtual Player Target { get; set; }
public virtual GameCountry Country { get; set; }
//Victims: Troops or Pops
public ICollection<Victim> Victims { get; set; }
public bool HasMoreWeaponsLeft { get; set; }
}
A victim can be a "Troop" object, or a "Population" object. What does the victim class have to look like? I could use 2 properties and set the unused one to "null" like this:
public class Victim
{
public virtual Troop TroopVictim { get; set; }
public virtual Population PopVictim { get; set; }
}
But that can't be the best solution, right? I want to determine that a Victim can be either a Troop or a Population.
I also thought about doing it via the setter:
public ICollection<object> Victims { get;
set
{
if (value.GetType() == typeof(Troop) || value.GetType() == typeof(Population))
Victims.Add(value);
}
}
But I still don't think that's the best way, or maybe it is... Is there a better, cleaner one?
Upvotes: 2
Views: 5385
Reputation: 71
You can use TypeConverter also.
//
// Summary:
// Converts a string into a font size.
//
// Remarks:
// To be added.
[TypeConversion(typeof(double))]
public class FontSizeConverter : TypeConverter, IExtendedTypeConverter
{
public FontSizeConverter();
//
// Summary:
// Converts a string representation of a font size into a font size.
//
// Parameters:
// value:
// The value to convert.
//
// Returns:
// To be added.
//
// Remarks:
// To be added.
public override object ConvertFromInvariantString(string value);
public override string ConvertToInvariantString(object value);
}
and use it like below:
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
get { return label.FontSize; }
set { label.FontSize = value; }
}
Then, you can assign string type or double type...
FontSize="Medium"
/*or*/
FontSize="24"
Upvotes: 0
Reputation: 895
Interfaces Mate!
public interface IVictim
{
string SharedProp { get; set; }
}
public class TroopVictim : IVictim
{
public string SharedProp { get; set; }
public string TroopProperty { get; set; }
}
public class PopVictim : IVictim
{
public string SharedProp { get; set; }
public string PopProperty { get; set; }
}
public class MyGenericVictim
{
//Optional Property
public bool? IsTroopVictim
{
get
{
if (Victim == null) return null;
return Victim.GetType() == typeof(TroopVictim);
}
}
public IVictim Victim { get; set; }
}
public class UseMyOfVictim
{
public void Bar()
{
Foo(new MyGenericVictim
{
Victim = new TroopVictim(),
});
}
public void Foo(MyGenericVictim myvic)
{
//Function doesnt know TroopVic or PopVic
TroopVictim resolvedTroopVic;
PopVictim resolvedPopVictim;
if (myvic.Victim.GetType() == typeof(TroopVictim))
{
resolvedTroopVic = (TroopVictim) myvic.Victim;
}
else if (myvic.Victim.GetType() == typeof(PopVictim))
{
resolvedPopVictim = (PopVictim) myvic.Victim;
}
string success = resolvedPopVictim.PopProperty;
success = resolvedTroopVic.TroopProperty;
}
}
Upvotes: 0
Reputation:
You could use interfaces.
public class WeaponUsed : HistoryEvent
{
public virtual Player Target { get; set; }
public virtual GameCountry Country { get; set; }
//Victims: Troops or Pops
public IVictim Victims { get; set; }
public bool HasMoreWeaponsLeft { get; set; }
}
public interface IVictim {
// common methods and properties for PopVictim and TroopVictim
int Number {get;}
}
public class TroopVictim : IVictim {
// TroopVictim will be enforced to have IVictim methods and proprieties
public int Number{ get {return 1; } }
}
public class PopVictim : IVictim {
// PopVictim will be enforced to have IVictim methods and proprieties
public int Number{ get {return 100; } }
}
Usage:
Console.WriteLine(weapon.Victims.Number)
Upvotes: 1