I have a class that has an ICollection property that is assigned by the constructor when the class is instantiated, but I want to bind this property to the original collection so that when it's updated/changed, the original list is as well. What is the best method of doing this?
Here's an example:
public class Organizations
{
private ICollection<Organization> _orgs;
public Organizations(ICollection<Organization> orgs)
{
_orgs = orgs;
}
public void TestAdd()
{
_orgs.Add(new Organization {Name = "Testing 123"});
}
}
// in another class
public ActionResult TestApi()
{
var tmp = new SyncTool.Core.Extensions.Zendesk.Organizations(ZendeskCache.Organizations.Data);
var zd = ZendeskCache.Organizations.Data.FirstOrDefault(n => n.Name.Contains("Testing 123"));
//ZendeskCache.Org.... is a List<Organization>
return Json(new {data = "tmp" }, AG);
}
The List<Organization> you are passing to the constructor is a reference object. This code works the way you want it to (aside from syntax errors), have you tried it out?
To reproduce more simply:
public class Program
{
public static void Main(string[] args)
{
var orgs = new List<string>();
var orgClass = new Organizations(orgs);
orgClass.TestAdd();
Console.WriteLine(orgs.First());
Console.Read();
}
}
public class Organizations
{
private ICollection<string> _orgs;
public Organizations(ICollection<string> orgs)
{
_orgs = orgs;
}
public void TestAdd()
{
_orgs.Add("Testing 123");
}
}
//Output: "Testing 123"
Related
I have a parent class called Snack with subclasses Drink and Sweets. I want to store my Snacks in a "VendingMachine" Class where there is a list for each of the Products. However, I don't want to write the same method for each type of Snack. How would you write this as a generic method ?
// DRINKS LIST
List<Drink> drinks = new List<Drink>();
public List<Drink> Drinks { get => drinks; set => drinks = value; }
private void FillWithProducts <Product> (params Product[] products) where Product : Snack
{
Type typeParameter = typeof(Product);
Type drink = typeof(Drink);
foreach (Product p in products)
{
if (typeParameter.Equals(drink))
{
Drinks.Add(p);
}
}
}
If you really need to store each kinds of products in theair own list, you can use a dynamically populated dictionary where the key is the type, something like this.
private readonly Dictionary<Type, List<Product>> storeByType = new();
public List<Drink> Drinks => (List<Drink>)this.storeByType[typeof(Drink)]
private void FillWithProducts<Product>(params Product[] products) where Product : Snack
{
foreach (Product p in products)
{
var key = p.GetType();
if (!this.storeByType.ContainsKey(key)) {
// ... add new List<T> instantiated by reflection
// use MakeGenericType + Activator.CreateInstance for example
}
// cast to the non-generic interface
var list = (IList)this.storeByType[key];
list.Add(p);
}
}
Note, that the code is just present as an example to demonstrate the idea, missing many checks and safety, and might not even work as is.
I would keep a dictionary inside the VendingMachine that holds the snacks of different types with the type as the key. By doing so you avoid having to search a list with mixed types every time you want to fetch the items.
static void Main(string[] args)
{
var m = new VendingMachine();
m.AddRange(new Drink(), new Drink());
m.AddRange(new Sweet());
var drinks = m.Fetch<Drink>();
var sweets = m.Fetch<Sweet>();
}
public class VendingMachine
{
private readonly Dictionary<Type, List<Snack>> _snacks = new();
public void AddRange<T>(params T[] snacks) where T : Snack
{
var type = typeof(T);
if (_snacks.TryGetValue(type, out var existingSnacks))
existingSnacks.AddRange(snacks);
else
_snacks.Add(type, new List<Snack>(snacks));
}
public List<T> Fetch<T>() where T : Snack
{
if (_snacks.TryGetValue(typeof(T), out var existingSnacks))
return new List<T>(existingSnacks.Cast<T>());
return new List<T>();
}
}
I think maybe there's a different way of doing this. With your base SnackBase base class and derived Drink and Sweet classes, you can fill a VendingMachine class with snacks then get the drink and sweet lists from the vending machine. The code below illustrates this:
Base Class
internal class SnackBase
{
public string Name { get; }
protected SnackBase(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentOutOfRangeException(nameof(name));
Name = name;
}
}
Derived classes
internal class Drink : SnackBase
{
public Drink(string name) : base(name) {}
}
internal class Sweet : SnackBase
{
public Sweet(string name) : base(name) {}
}
VendingMachine.cs
internal class VendingMachine
{
private readonly List<SnackBase> _snacks;
public VendingMachine(List<SnackBase> snacks)
{
_snacks = snacks;
}
public List<SnackBase> GetDrinks()
{
return _snacks.Where(s => s.GetType().Name == nameof(Drink)).ToList();
}
public List<SnackBase> GetSweets()
{
return _snacks.Where(s => s.GetType().Name == nameof(Sweet)).ToList();
}
}
Program.cs
internal static class Program
{
public static void Main()
{
var snacks = new List<SnackBase>
{
new Drink("Coke"),
new Sweet("Snickers"),
new Drink("Pepsi"),
new Sweet("Mars Bar"),
new Drink("7 Up"),
new Sweet("Reece's Pieces")
};
var vendingMachine = new VendingMachine(snacks);
Console.WriteLine("Drinks");
Console.WriteLine("------");
var drinks = vendingMachine.GetDrinks();
foreach (var drink in drinks)
{
Console.WriteLine(drink.Name);
}
Console.WriteLine("Sweets");
Console.WriteLine("------");
var sweets = vendingMachine.GetSweets();
foreach (var sweet in sweets)
{
Console.WriteLine(sweet.Name);
}
}
}
The vending machine class only needs one list of the common type (Snack)
Snacks
public abstract class Snack
{
protected Snack(string name)
{
Name = name;
}
public string Name { get; }
public abstract override string ToString();
}
public class Sweet : Snack
{
public Sweet(string name) : base(name)
{
}
public override string ToString() => $"Sweet({Name})";
}
public class Drink : Snack
{
public Drink(string name) : base(name)
{
}
public override string ToString() => $"Drink({Name})";
}
Vending Machine
public class VendingMachine
{
readonly List<Snack> _snacks;
public VendingMachine(params Snack[] snacks) => _snacks = new List<Snack>(snacks);
public VendingMachine(IEnumerable<Snack> snacks) => _snacks = new List<Snack>(snacks);
public IReadOnlyList<Snack> Snacks { get => _snacks; }
public IReadOnlyList<Drink> Drinks { get => _snacks.OfType<Drink>().ToList(); }
public IReadOnlyList<Sweet> Sweets { get => _snacks.OfType<Sweet>().ToList(); }
public void AddDrink(string name) => _snacks.Add(new Drink(name));
public void AddSweet(string name) => _snacks.Add(new Sweet(name));
}
Test Program
static class Program
{
static void Main(string[] args)
{
var vend = new VendingMachine();
vend.AddDrink("Joke Cola");
vend.AddSweet("Mersa Bar");
vend.AddDrink("Diet Goo");
vend.AddDrink("Bronto Care");
vend.AddSweet("Broken Tooth");
Console.WriteLine("Vending Machine Sweets");
foreach (var item in vend.Sweets)
{
Console.WriteLine(item);
}
Console.WriteLine();
Console.WriteLine("Vending Machine Drinks");
foreach (var item in vend.Drinks)
{
Console.WriteLine(item);
}
}
}
Sample Output
Vending Machine Sweets
Sweet(Mersa Bar)
Sweet(Broken Tooth)
Vending Machine Drinks
Drink(Joke Cola)
Drink(Diet Goo)
Drink(Bronto Care)
I want to call many tests like this.
var test8001 = new Test8001();
test8001.Execute(drv);
var test8002 = new Test8002();
test8002.Execute(drv);
var test8007 = new Test8007();
test8007.Execute(drv);
How can I automatically instantiate all test function with a int list of all test numbers?
List<int> classNameNumbers = new List<int>() { 8001, 8002, 8007 };
I need a for-loop where Execute() is called on every instance.
Edit:
The name of the type e.g. 'Test8001' should be retrieved from my integer list.
Try out the following
namespace Stackoverflow46529447
{
class Program
{
static void Main(string[] args)
{
var drv = new Drv();
var numbers = new[] {8001, 8002, 8003};
var executables = numbers.Select(x => Activator.CreateInstance(Type.GetType($"Stackoverflow46529447.Test{x:0000}")))
.OfType<IExecutable>()
.ToArray();
foreach (var executable in executables)
{
executable.Execute(drv);
}
}
}
public class Test8001 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8001");
}
}
public class Test8002 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8002");
}
}
public class Test8003 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8003");
}
}
public interface IExecutable
{
void Execute(Drv drv);
}
public class Drv
{
}
}
This uses reflection to create instance types.
I am using.Net 2.0
I have a generic
List< MyContainerObject > MyList;
and
MyContainerClass MyContainerObject = new MyContainerClass();
and
Public Class MyContainerClass
{
public BasicClass BasicObject;
public AdvanceClass AdvanceObject
}
How can I search for BasicObject in MyList efficiently?
Sample Code added
namespace WindowsApplication4
{
public class Program
{
private List<ContainerClass> MyList;
public Program()
{
MyList = new List<ContainerClass>();
}
private void Add(object sender, EventArgs e)
{
ContainerClass objContainer1 = new ContainerClass("B1","A1");
ContainerClass objContainer1 = new ContainerClass("B2", "A2");
MyList.Add(objContainer1);
MyList.Add(objContainer2);
}
private void Get(BasicClass objBasic)
{
//How to retreive ContainerClass from MyList that has objBasic ??
}
}
public class ContainerClass
{
private BasicClass BasicObject;
private AdvancedClass AdvancedObject;
public ContainerClass(string baseID, string AdvanceID)
{
BasicObject = new BasicClass();
BasicObject.ID = baseID;
AdvancedObject = new AdvancedClass();
AdvancedObject.ID = AdvanceID;
}
}
public class BasicClass
{
public string ID;
public int name;
}
public class AdvancedClass
{
public string ID;
public int name;
}
}
I think it would be very nice if you would be using .Net version higher than 2.0 than you caould use the linq to simply get the object you want rom the list.
but you can use delegate and find method
http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx
could be something like
MyContainerClass MyContainerObject = MyList.Find(delegate(MyContainerClass p) {return
BasicObject.Val == someval; });
var found = MyList.FirstOrDefault(o => o.BasicObject == someObject);
Note that unless BasicObject implement IEquatable<BasicObject> and/or overloads Equals/operator== you end up with object.ReferenceEquals(o.BasicObject, someObject) effectively.
Oops. .NET 2.0. Well:
BasicObject FindBy(List<MyContainerClass> list, BasicObject o)
{
foreach (MyContainerClass i in list)
{
if (i.BasicObject == o) // same caveats on Equality
return i;
}
return null;
}
This code:
public interface IInter { }
public class Concrete : IInter { /*... body ...*/ }
var t = (List<IInter>)new List<Concrete>();
Yields this error:
Cannot convert type 'System.Collections.Generic.List<Concrete>' to 'System.Collections.Generic.List<IInter>'
Why is it ? how do I overcome it ? my goal is this:
var t = new List<List<IInter>>()
{
new List<ConcreteA>(){/* ... data ... */},
new List<ConcreteB>(){/* ... data ... */},
// ...
new List<ConcreteX>(){/* ... data ... */},
};
Edit:
Thanks for all your help. Ahh, I kinda abstracted things, to make it easier to read... but my real problem is this:
public class SingletonFactory<T> where T : IToken
{
private SingletonFactory() { }
private static SingletonFactory<T> _instance = new SingletonFactory<T>();
public static SingletonFactory<T> Instance { get { return _instance; } }
public T Produce(int position) { return (T)Activator.CreateInstance(typeof(T), position); }
public T Produce(int position, string token) { return (T)Activator.CreateInstance(typeof(T), position, token); }
}
And then:
var keywords = new Dictionary<string, SingletonFactory<IToken>>()
{
{ "abc", SingletonFactory<Abc>.Instance },
{ "xyz", SingletonFactory<Xyz>.Instance },
{ "123", SingletonFactory<Num>.Instance }
};
So I guess it's much more complicated...
I'm using c# 4.0
var res = new List<Concrete>().Cast<IInter>().ToList();
A List<Concrete> is not a List<IInter> although Concrete implements IInter.
You can use:
List<IInter> t = ConcreteList.Cast<IInter>().ToList();
Covariance and Contravariance FAQ
Because you cannot assign a List<ConcreteA> to a List<IInter>, otherwise you could do this:
concreteAList = newList<ConcreteA>();
List<Inter> interList = concreteAList as List<Inter>; // seems harmless
interList.Add(new ConcreteB()); // not allowable
You could do:
var t = new List<List<IInter>>()
{
new List<IInter>(){/* ... fill with ConcreteAs ... */},
new List<IInter>(){/* ... fill with ConcreteBs ... */},
// ...
new List<IInter>(){/* ... fill with ConcreteXs ... */},
};
But I don't know if that accomplishes what you want.
This is called covariance and C# supports covariance (and contravariance) on generic interfaces and not generic classes. This is the following works but your example does not:
IEnumerable<IInter> e = new List<Concrete>();
ICollection<IInter> c = new List<Concrete>();
Covariance is also supported on arrays:
IInter[] a = new Concrete[3];
Make a covrariant interface for the methods you need to access from SingletonFactory<T>. This will ensure that your type T is output type safe.
public interface IToken { }
public class Abc : IToken { }
public class Xyz : IToken { }
public class Num : IToken { }
public interface ISingletonFactory<out T> where T : IToken
{
T Produce(int position);
T Produce(int position, string token);
}
public class SingletonFactory<T> : ISingletonFactory<T> where T : IToken
{
private SingletonFactory() { }
private static SingletonFactory<T> _instance = new SingletonFactory<T>();
public static SingletonFactory<T> Instance { get { return _instance; } }
public T Produce(int position) { return (T)Activator.CreateInstance(typeof(T), position); }
public T Produce(int position, string token) { return (T)Activator.CreateInstance(typeof(T), position, token); }
}
var keywords = new Dictionary<string, ISingletonFactory<IToken>>()
{
{ "abc", SingletonFactory<Abc>.Instance },
{ "xyz", SingletonFactory<Xyz>.Instance },
{ "123", SingletonFactory<Num>.Instance }
};
One way is:
IEnumerable<IInter> t = new List<Concrete>();
Another is:
List<IInter> t = new List<Concrete>().ConvertAll(x => (IInter) x);
Edit, adding better sample to show that it works (the test passes):
[Test]
public void CovarianceTest()
{
var concrete = new Concrete();
IEnumerable<IInter> t = new List<Concrete> { concrete };
Assert.IsTrue(new[] { concrete }.SequenceEqual(t));
List<IInter> t2 = new List<Concrete> { concrete }.ConvertAll(x => (IInter)x);
Assert.IsTrue(new[] { concrete }.SequenceEqual(t2));
}
If I have a Class like below. How do i traverse through it until its property SomeObjects.count = 0
public class SomeObject
{
public String Name { get; set; }
public List<SomeObject> SomeObjects { get; set; }
}
Many Thanks
Here is a generic example of how you can traverse a composite object:
public static class TraversalHelper{
public static void TraverseAndExecute<T>(this T composite, Func<T,IEnumerable<T>> selectChildren, Action<T> action)
where T: class
{
action.Invoke(composite);
composite.TraverseAndExecute(selectChildren, action, new List<T>{ composite });
}
private static void TraverseAndExecute<T>(this T composite, Func<T,IEnumerable<T>> selectChildren, Action<T> action, IList<T> invokedComponents)
where T: class
{
invokedComponents = invokedComponents ?? new List<T>();
var components = selectChildren(composite) ?? new T[]{};
foreach(var component in components){
// To avoid an infinite loop in the case of circular references, ensure
// that you don't loop over an object that has already been traversed
if(!invokedComponents.Contains(component)){
action.Invoke(component);
invokedComponents.Add(component);
component.TraverseAndExecute<T>(selectChildren, action, invokedComponents);
}
else{
// the code to execute in the event of a circular reference
// would go here
}
}
}
}
Here is a sample usage:
public class Program{
public static void Main(){
var someObject = new SomeObject {
Name = "Composite",
SomeObjects = new List<SomeObject>{
new SomeObject{ Name = "Leaf 1" },
new SomeObject{
Name = "Nested Composite",
SomeObjects = new List<SomeObject>{ new SomeObject{Name = "Deep Leaf" }}
}
}
};
someObject.TraverseAndExecute(
x => x.SomeObjects,
x => { Console.WriteLine("Name: " + x.Name); }
);
}
}
This is a tree-like structure; there are many algorithms for traversing it, you can search for tree-traversal algorithms and you'll find many of them.