How to pass generic field to observable collection - c#

I have code as follows
public class Field<T>
{
private T_fieldValue;
public T FieldValue
{
get
{
return _fieldValue;
}
set
{
_fieldValue = value;
}
}
}
public class Container
{
private ObservableCollection<Field> _fieldValues;
public ObservableCollection<Field> FieldValues
{
get { return _fieldValues; }
set { _fieldValues = value; }
}
}
How can I pass my Type parameter in container class as well ??
i.e I am looking for something like
private ObservableCollection<Field<T>> _fieldValues;
EDIT:
I made changes to the class as follows
public class Container<T>
{
public string MyName { get; set; }
private ObservableCollection<Field<T>> _fieldValues;
public ObservableCollection<Field<T>> FieldValues
{
get { return _fieldValues; }
set { _fieldValues = value;}
}
}
}
Now in my Main class how can i call something like
new ObservableCollection<Container>() { MyName ="Kyle",
new Container() { FieldValues = new ObservableCollection<Field<int>>()
{new Field<int>(){FieldValue=10}}; // I am not sure if this syntax is correct

You will need to make the Container class generic as well:
class Container<T> : BindableBase
{
private ObservableCollection<Field<T>> _fieldValues;
}
If you always have a specific T parameter type in mind for Container, then you can of course just hard-code that:
class Container : BindableBase
{
private ObservableCollection<Field<SomeSpecificType>> _fieldValues;
}
To create an instance of your generic Container<T> class, you use the exact same syntax you'd use for any generic type. For example, if T is int, you would use:
new Container<int>()
Then you can assign the FieldValues property as you indicate in your updated example. I.e.:
FieldValues = new ObservableCollection<Field<int>>()

Related

How to use Inheritance Abstract Class?

I need some help with an example of Inheritance class (abstract). I can't use my function ToCSV() because i return a list of BananaPart and C# wants a list of FruitPart. How is it possible to solve this ?
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
FruitFactory fruitFactory = new FruitFactory();
Fruit myFruit = fruitFactory.Create("banana");
myFruit.FruitPart.ForEach(f => Console.WriteLine(f.ToString()));
}
}
public class FruitFactory {
public Fruit Create(string fruitType) {
switch(fruitType) {
case "banana":
return new Banana();
break;
default:
throw new Exception("undefined fruitType");
}
}
}
public abstract class Fruit {
protected string _name;
protected List<FruitPart> _fruitPart;
public Fruit() {
this._name = "A fruit";
}
public string Name { get { return this._name; } }
public List<FruitPart> FruitPart { get { return this._fruitPart; } }
}
public abstract class FruitPart { }
public class Banana : Fruit {
public Banana() : base() {
this._name = "banana";
this._fruitPart = ToCSV();
}
public List<BananaPart> ToCSV(){
return new List<BananaPart> { new BananaPart(5, "10"), new BananaPart(10, "20"), new BananaPart(20, "40") };
}
}
public class BananaPart : FruitPart {
private int _seed;
private string _dimensionPart;
public BananaPart (
int seed,
string dimensionPart
) {
this._seed = seed;
this._dimensionPart = dimensionPart;
}
}
It will be a pleasure for me to learn more about it ! Thank you in advance !
The reason that your code is not compiling is because List<T> is not covariant. In order to compile your code you need to change List<T> with IEnumerable<T> which has a covariant type parameter. So the changes are:
public abstract class Fruit {
protected string _name;
protected IEnumerable<FruitPart> _fruitPart;
public Fruit() {
this._name = "A fruit";
}
public string Name { get { return this._name; } }
public IEnumerable<FruitPart> FruitPart { get { return this._fruitPart; } }
}
You can learn more about covariance here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/
In short, covariance lets you deduce the assignment compatibility of two types based on the assignment compatibility of two other types. Since, we can assign a BananaPart to a FruitPart, we can deduce that a IEnumerable<BananaPart> can be assigned to IEnumerable<FruitPart>.
There is a problem in your model. Say I have a Banana, and it has a list of fruit-parts. Now I could call myBananana.FruitParts.Add(new ApplePart()), this cannot work since a banana is only composed of bananaparts.
To avoid this you need to be more restrictive in what you return. Instead of using a List<FruitPart> you could use IEnumerable<Fruitpart>. This avoids the problem since you cannot add anything to a IEnumerable.
If you are learning I would also recommend starting with interfaces instead of abstract classes. The later is sometimes called "Implementation inheritance", i.e. it is used to share code between two derived classes. This is sometimes useful, but in the majority of cases it is better to put this shared code in a third class, sometimes called "Composition over inheritance".
Your fruit could ook something like this using interfaces:
public interface IFruit
{
string Name { get; }
IEnumerable<IFruitPart> FruitPart { get; }
}
public class Banana : IFruit
{
public Banana() : base() => FruitPart = ToCSV();
public static List<BananaPart> ToCSV() => new List<BananaPart> { new BananaPart(5, "10"), new BananaPart(10, "20"), new BananaPart(20, "40") };
public string Name { get; } = "Banana";
public IEnumerable<IFruitPart> FruitPart { get; }
}
public interface IFruitPart { }
public class BananaPart : IFruitPart
{
public int Seed { get; }
public string DimensionPart { get; }
public BananaPart(int seed, string dimensionPart) => (Seed, DimensionPart) = (seed, dimensionPart);
}
Notice that you do not need much more code for the interface variant compared to the abstract class case.
You cannot safely cast List<Child> to List<Parent> because it would let you add Apple to List<Banana>.
You can create List<FuitPart> instead.
public List<FruitPart> ToCSV()
{
return new List<FruitPart> {
new BananaPart(5, "10"),
new BananaPart(10, "20"),
new BananaPart(20, "40") };
}
As List<BananaPart> doesn't inherite List<FruitPart> you can't do it like that.
I'll suggest you to make some wrapper classes, like FruitedDetails and BananaDetails that would inherite it. That way you could encapsulate the specific details of classes you are working with and wouldn't have to deal with various casting of objects when you pack your lists.

Simplify Constructor for class with multiple initialisable fields

I currently have the following problem:
I have a class which includes 3 different fields
Enum x
ActiveDirectoryUser y
CustomClass z
The enum can be initialised by passing a string or the enum object.
The ADUser can be initialised by passing a string (LoginName) or the user by itself and the CustomClass can be initialized by passing a string, int or the object.
Now I want to initialize the class to pass all different combinations like
class(string enumValue, string adUser, string customClass)
class(string enumValue, ADUser adUser, CustomClass customClass)
class(EnumValue enumValue, string adUser, CustomClass customClass)
Is there a way to simplify the constructors without typing all of the 12 possibilities (Enum-2 * ADUser-2 * CClass-3 = 12)?
I thought about chained constructors where i also ended up with 12 constructors but also thought about just passing the c# Object on each parameter and cast it and do stuff with it but i think that is just a dirty workaround?
Edit
The class is contained in an library and so can be used internal but also public. For the internal uses there is no problem to pass a concrete version of an object.
But if i use it public in other solutions these solutions can only refer to string or int values. So the class should be able to 'take' the values and convert them while beeing initialised because it have access to all the real objects.
Maybe this clarifies the problem a bit.
Here some code snippets with changed names:
#region Content of libraryOne
public class ClassName
{
internal EnumValueWrapper { get; set; }
internal CustomClass { get; set; }
internal ADUser { get; set; }
public ClassName() { ... } //Now via Builder Pattern
internal ClassName() { ... } //With Parameters for internal initialisations
public InformationContainer GetContentInfo()
{
//[...]Process Stuff and Return Container
}
}
internal CustomClass { ... }
internal EnumValueWrapper { ... }
internal ADUser { ... }
#endregion Content of libraryOne
If your class has only 3 properties (EnumValue, ADUser, CustomClass) then you should have only one constructor with these :class(EnumValue enumValue, ADUser adUser, CustomClass customClass). The ADUser and CustomClass should be instantiated outside of your class using their constructor which support string or int, etc;
Example:
class (EnumValue param, new ADUser(string_param), new CustomClass(int_param));
class (EnumValue param, new ADUser(ADUser_param), new CustomClass(string_param));
Edit
You can use it like I described above for internal scope and for the public part you can use and expose a factory (wrapper) class which actually can receive users and other parameters as strings or int and internally instantiate and return your class.
In addition to your snippet: Create a proxy like public class in your assembly that can be accessed from outside (from other assemblies).Make your class internal:
public class ClassNameBuilder
{
private ClassName _className;
public ClassNameBuilder(string enumValue, string user, string custom_class)
{
_className = new ClassName(EnumToString, new User(user), new CustomClass(custom_class));
}
public void CallClassNameMethod1()
{
return _className.Method1()
}
public void CallClassNameMethod2()
{
return _className.Method2()
}
}
The builder class can use whatever method you want to build the ClassName object; This way you can expose all your class methods without using multiple constructors.
I think the best thing to do is use the Builder pattern. You can even use it with derived classes.
My classes to build:
public class MyBaseClass
{
public MyBaseClass(SomeEnum enumValue, User user)
{
}
}
public class MyDerivedClass : MyBaseClass
{
public MyDerivedClass(SomeEnum enumValue, User user, CustomClass customStuff)
: base(enumValue, user)
{
}
}
Now let's add a builder class featuring an additional extension class for making things much more comfortable (it's sort of an extended Builder pattern using C# extension method wizadry):
public class MyBaseClassBuilder
{
public SomeEnum EnumValue { get; set; }
public User User { get; set; }
}
public static class MyBaseClassBuilderExtensions
{
public static T SetEnumValue<T>(this T instance, SomeEnum value)
where T : MyBaseClassBuilder
{
instance.EnumValue = value;
return instance;
}
public static T SetEnumValue<T>(this T instance, string value)
where T : MyBaseClassBuilder
{
instance.EnumValue = (SomeEnum)Enum.Parse(typeof(SomeEnum), value);
return instance;
}
public static T SetUser<T>(this T instance, User value)
where T : MyBaseClassBuilder
{
instance.User = value;
return instance;
}
public static T SetUser<T>(this T instance, string value)
where T : MyBaseClassBuilder
{
instance.User = new User(value);
return instance;
}
public static MyBaseClass Build(this MyBaseClassBuilder instance)
{
return new MyBaseClass(instance.EnumValue, instance.User);
}
}
Now let's do the same thing for our derived class:
public class MyDerivedClassBuilder : MyBaseClassBuilder
{
public CustomClass CustomStuff { get; set; }
}
public static class MyDerivedClassBuilderExtensions
{
public static T SetCustomStuff<T>(this T instance, CustomClass value)
where T : MyDerivedClassBuilder
{
instance.CustomStuff = value;
return instance;
}
public static T SetCustomStuff<T>(this T instance, string value)
where T : MyDerivedClassBuilder
{
instance.CustomStuff = new CustomClass(value);
return instance;
}
public static MyDerivedClass Build(this MyDerivedClassBuilder instance)
{
return new MyDerivedClass(instance.EnumValue, instance.User, instance.CustomStuff);
}
}
Now you can construct your instances in some fluent API style way:
static void Main(string[] args)
{
MyBaseClass baseInstance = new MyBaseClassBuilder()
.SetEnumValue("Alpha")
.SetUser("Big Duke")
.Build();
MyDerivedClass derivedInstance = new MyDerivedClassBuilder()
.SetEnumValue(SomeEnum.Bravo)
.SetUser(new User("Lt. Col. Kilgore"))
.SetCustomStuff("Smells like victory")
.Build();
}
Finally the additional types:
public enum SomeEnum
{
Alpha,
Bravo
}
public class User
{
public User(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
public class CustomClass
{
public CustomClass(string notation)
{
this.Notation = notation;
}
public string Notation { get; private set; }
}
This way you can construct instances which require many constructor arguments in a comfortable way.

Can I have my inheriting class acquire the property values of a parent class instance with less code than this?

I need the separate classes for Xml Serialization. I'd like to know if there is a simpler way for the inheriting BuildingDetail class to acquire the property values from the parent Building class.
Parent Class
public class Building
{
public int BuildingId;
public string BuildingName;
protected Building()
{
}
private Building(int buildingId, string buildingName)
{
BuildingId = buildingId;
BuildingName = buildingName;
}
public static Building Load(int buildingId)
{
var dr = //DataRow from Database
var building = new Building(
(int) dr["BuildingId"],
(string) dr["BuildingName"]);
return building;
}
}
Inheriting Class
public class BuildingDetail : Building
{
public BaseList<Room> RoomList
{
get { return Room.LoadList(BuildingId); }
}
protected BuildingDetail()
{
}
// Is there a cleaner way to do this?
private BuildingDetail(int buildingId, string buildingName)
{
BuildingId = buildingId;
BuildingName = buildingName;
}
public new static BuildingDetail Load(int buildingId)
{
var building = Building.Load(buildingId);
var buildingDetail = new BuildingDetail(
building.BuildingId,
building.BuildingName
);
return buildingDetail;
}
}
Thanks.
Firstly, change your base class constructor access modifier to protected. And then you can call base class constructor with base keyword:
private BuildingDetail(int buildingId, string buildingName)
: base(buildingId, buildingName)
{
...
}
It will call the base constructor first. Also if you don't put the :base(param1, param2) after your constructor, the base's empty constructor will be called.

DotLiquid - access an collection element via a string indexer?

Is it possible to access a collection item by a string reference instead of an index offset for DotLiquid?
public class MyItem
{
public string Name;
public object Value;
public MyItem(string Name, object Value)
{
this.Name = Name;
this.Value = Value;
}
}
public class MyCollection : List<MyItem>
{
public MyCollection()
{
this.Add(new MyItem("Rows", 10));
this.Add(new MyItem("Cols", 20));
}
public MyItem this[string name]
{
get
{
return this.Find(m => m.Name == name);
}
}
}
So in normal c# if I create an instance of the MyCollection class I can access the elements like this
MyCollection col =new MyCollection();
col[1] or col["Rows"]
Can I access via the name element col["Rows"] in a DotLiquid template? If so how do I implement this?
Yes, it is possible. First, define a Drop class like this:
public class MyCollectionDrop : Drop
{
private readonly MyCollection _items;
public MyCollectionDrop(MyCollection items)
{
_items = items;
}
public override object BeforeMethod(string method)
{
return _items[method];
}
}
Then, in the code that renders your template, add an instance of it to the context:
template.Render(Hash.FromAnonymousObject(new { my_items = new MyCollectionDrop(myCollection) }));
Finally, access it like this in your template:
{{ my_items.rows.name }}
"rows" will be passed as-is to MyCollectionDrop.BeforeMethod as the method argument.
Note that you'll also need to make MyItem inherit from Drop, to be able to access its properties. Or write a MyItemDrop class like this:
public class MyItemDrop : Drop
{
private readonly MyItem _item;
public MyItemDrop(MyItem item)
{
_item = item;
}
public string Name
{
get { return _item.Name; }
}
public string Value
{
get { return _item.Value; }
}
}
and then change MyCollectionDrop.BeforeMethod to this:
public override object BeforeMethod(string method)
{
return new MyItemDrop(_items[method]);
}

C# Object Inheritance

I am trying to create a base class in c# that I can extend out to sub classes.
For example:
public class ObjectsInTheSky
{
public string Size, Shape;
public float Mass;
public int DistanceFromEarth;
public bool hasAtmosphere, hasLife;
public enum ObjectTypes {Planets,Stars,Moons}
public ObjectsInTheSky( int id )
{
this.Load( id );
}
public void Load( int id)
{
DataTable table = Get.DataTable.From.DataBase(id);
System.Reflection.PropertyInfo[] propInfo = this.GetType().GetProperties();
Type tp = this.GetType();
foreach (System.Reflection.PropertyInfo info in propInfo)
{
PropertyInfo p = tp.GetProperty(info.Name);
try
{
if (info.PropertyType.Name == "String")
{
p.SetValue(this, table.Rows[0][info.Name].ToString(), null);
}
else if (info.PropertyType.Name == "DateTime")
{
p.SetValue(this, (DateTime)table.Rows[0][info.Name], null);
}
else
{
p.SetValue(this, Convert.ToInt32(table.Rows[0][info.Name]), null);
}
}
catch (Exception e)
{
Console.Write(e.ToString());
}
}
}
}
public class Planets : ObjectsInTheSky
{
public Moons[] moons;
}
public class Moons : ObjectsInTheSky
{
}
public class Stars : ObjectsInTheSky
{
public StarTypes type;
public enum StarTypes {Binary,Pulsar,RedGiant}
}
My problem is when I try to use an object:
Stars star = new Stars(142);
star.type does not exists and property of star, it exists as star.star.type but completely inaccessable, or I can not figure out how to access it.
I do not know if I'm extending the ObjectsInTheSky property properly or not. Any help or pointers will be greatly appreciated.
It looks as though you are trying to use a constructor that is not defined on your subclass Stars or the base class.
Stars star = new Stars(142);
If you are trying to use the .Load(int) method then you would need to do this:
Stars star = new Stars();
star.Load(142);
Or, if you are trying to use the base constructor, you need to define it in the subclass:
public class Stars : ObjectsInTheSky
{
public Stars(int id) : base(id) // base class's constructor passing in the id value
{
}
public Stars() // in order to not break the code above
{
}
public StarTypes type;
public enum StarTypes {Binary,Pulsar,RedGiant}
}
Constructors in C# are not inherited. You need to add the additional constructor overloads to each of the base classes:
public class Stars : ObjectsInTheSky
{
public Stars(int id) : base(id) { }
public StarTypes type;
public enum StarTypes {Binary,Pulsar,RedGiant}
}
This will create a constructor that just calls the base class's constructor for you.

Categories