I have classes:
public class Throw
{
public double speed { get; set; }
public double accurency { get; set; }
}
public class FastThrow : Throw{}
public class LowThrow : Throw{}
Instead of having:
public static FastThrow SetFastThrow(List<object> args)
{
return new FastThrow
{
speed = (double)args[0],
accurency = (double)args[1]
};
}
public static LowThrow SetLowThrow(List<object> args)
{
return new LowThrow
{
speed = (double)args[0],
accurency = (double)args[1]
};
}
I want to have one with parent class:
public static Throw SetThrow(List<object> args)
{
return new Throw
{
speed = (double)args[0],
accurency = (double)args[1]
};
}
To declare list or some other generic interface with child class with instance of parent class. Then adding new elements to existing collection. I know that below example has compilation errors, but it should look like:
List<List<object>> firstList = new List<List<object>>();
public void Main()
{
IList<FastThrow> secondList = new List<Throw>();
foreach (var item in firstList)
{
secondList.Add(SetThrow(item));
}
}
I read about contravariance and do not know if this is possible.
You can't. Rahter than
To declare list or some other generic interface with child class with
instance of parent class.
you should
To declare list or some other generic interface with parent class with
instance of chidlren class.
The second way, as Anirban said, use generic classes, refactor your SetThrow method as following:
public static T SetThrow<T>(List<object> args) where T : Throw, new()
{
return new T
{
speed = (double)args[0],
accurency = (double)args[1]
};
}
So that you can use SetThrow method only to generate different kinds of classes as long as they are child classes. e.g:
IList<FastThrow> secondList = new List<FastThrow>();
foreach (var item in firstList)
{
secondList.Add(SetThrow<FastThrow>(item));
}
And generic classes are strong typed and elegant to use.
Related
I had a class which represents a prefix search tree:
public class PrefixTree<TData>
{
private PrefixTree<TData>[] _children;
private void SomeMethod()
{
_children = new PrefixTree<TData>[10];
}
}
Then I created a derived class with additional features for its nodes:
public class NewPrefixTree<TData> : PrefixTree<TData>
The problem is that in SomeMethod() of derived class we still create instances of base class and it doesn't fit the meaning.
I refactored the base class to this:
public abstract class PrefixTree<TData, TNode>
where TNode : PrefixTree<TData, TNode>, new()
{
private TNode[] _children;
private void SomeMethod()
{
_children = new TNode[10];
}
}
Despite the base class has complete functionality itself, I had to make it abstract because I can't write new DigitalPrefixTree<TData, DigitalPrefixTree<int, ...>>() .
But now I can use it this way and it works perfectly:
public class NewPrefixTree<TData> : PrefixTree<TData, NewPrefixTree<TData>> {} // for derived class
//or
public class PrefixTree<TData> : PrefixTree<TData, PrefixTree<TData>> {} // to use the base functionality
I've never done this before and I wonder if it's a good idea to declare a class with generic parameter of the same generic class type. Or I need to make some tricks with co/contra-variance of generic interfaces (but it probably doesn't work as I use the class type as method’s parameters type and as return type as well)?
Try this:
public interface INode<out TData>
{
TData Data { get; }
IEnumerable<INode<TData>> Children { get; }
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>();
}
public interface ITree<out TData>
{
IEnumerable<INode<TData>> Children { get; }
IEnumerable<TRequiredData> GetNestedData<TRequiredData>();
}
public class Node<TData> : INode<TData>
{
public TData Data { get; }
public IEnumerable<INode<TData>> Children { get; }
public Node(TData data, IEnumerable<INode<TData>>? children = null)
{
Data = data;
Children = children ?? Enumerable.Empty<INode<TData>>();
}
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>()
{
List<TRequiredData> result = new();
if (Data is TRequiredData requiredData)
result.Add(requiredData);
foreach (var child in Children)
result.AddRange(child.GetNestedData<TRequiredData>());
return result;
}
}
public class Tree<TData> : ITree<TData>
{
public IEnumerable<INode<TData>> Children { get; }
public Tree(IEnumerable<INode<TData>> children)
{
Children = children;
}
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>()
{
List<TRequiredData> result = new();
foreach (var node in Children)
result.AddRange(node.GetNestedData<TRequiredData>());
return result;
}
}
And here is example of usage:
record SomeRecord();
class SomeClass {}
static void Main(string[] args)
{
var nodeWithNested = new Node<SomeClass>(
data: new SomeClass(),
children: new List<INode<SomeClass>>()
{
new Node<SomeClass>(new SomeClass()),
new Node<SomeClass>(new SomeClass())
});
var nodes = new List<INode<object>>()
{
new Node<SomeClass>(new SomeClass()),
nodeWithNested,
new Node<SomeRecord>(new SomeRecord()),
};
var tree = new Tree<object>(nodes);
var someClasses = tree.GetNestedData<SomeClass>(); // 4 items
var someRecords = tree.GetNestedData<SomeRecord>(); // 1 item
}
This approach based on out generic modifier.
The only restriction is that you can not use structs (int, bool and ect.) as they don't have common object to cast to.
Hope this will be useful.
I have a class that contains a list of items (implement IHasItems). In a specific scenario, I want to hide these items by explicit implement IHiddenItems to return empty list.
But there is an existing method (PrintItems - in this case), the input parameter type is IHasItems. Consequently, the items can not be hidden in the method even if I cast the object to IHiddenItems.
The reason to try this approach is that I don't want to create a prototype of this object and set it empty in the prototype instance.
public interface IHasItems
{
IEnumerable<string> Items { get; }
}
public interface IHiddenItems : IHasItems
{
new IEnumerable<string> Items { get; }
}
public class Implementation : IHasItems, IHiddenItems
{
public Implementation()
{
Items = new List<string>()
{
"A","B","C"
};
}
public IEnumerable<string> Items { get; }
IEnumerable<string> IHiddenItems.Items { get; } = new List<string>(); // Empty
}
static class Program
{
static void Main()
{
Implementation derivedClass = new Implementation();
Console.WriteLine($"Implementation: {derivedClass.Items.Count()}");
Console.WriteLine($"IHasList: {((IHasItems)derivedClass).Items.Count()}");
Console.WriteLine($"IEmptyList: {((IHiddenItems)derivedClass).Items.Count()}");
PrintItems(((IHiddenItems)derivedClass));
Console.Read();
}
public static void PrintItems(IHasItems obj)
{
Console.WriteLine($"PrintItems method: {obj.Items.Count()}");
}
}
Result
Implementation: 3
IHasList: 3
IEmptyList: 0
PrintItems method: 3
Expected
Without modify PrintItems, it should display to console PrintItems method: 0
I have a class called Animals what contains two List<T>.
One is a list of bears, and one is a list of pinguins.
I can pretty trivially get the list of bears by just calling Bears on the animals variable - but how do I get it via reflection?
I have created a static helper class ListHelper, with a generic method that takes either Bear or Pinguin as the generic type, and animals as the argument which should return the list of bears if Bear is the generic type.
That doesn't happen. Instead it crashes with this message
: System.Reflection.TargetException: 'Object does not match target type, and I cannot understand why, because the type is correct when I inspect it via the debugger.
Fully "working" example below.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System;
class ReflectionTrouble
{
static void Main(string[] args)
{
var animals = new Animals
{
Bears = new List<Bear> {new Bear {Name = "Bear1"}, new Bear {Name = "Bear 2"}},
Pinguins = new List<Pinguin> {new Pinguin {Name = "Pingo1"}, new Pinguin {Name = "Pingo2"}}
};
var lists = ListHelper.GetList<Bear>(animals);
foreach (var bear in lists)
{
Console.WriteLine(bear.Name);
}
//expected to have printed the names of the bears here...
}
}
public static class ListHelper
{
public static IEnumerable<T> GetList<T>(Animals animals)
{
var lists = animals.GetType().GetRuntimeProperties().Where(p => p.PropertyType.IsGenericType);
foreach (var propertyInfo in lists)
{
var t = propertyInfo.PropertyType;
var typeParameters = t.GetGenericArguments();
foreach (var typeParameter in typeParameters)
{
if (typeParameter == typeof(T))
{
// This is where it crashes.
var list = (IEnumerable<T>) propertyInfo.GetValue(t);
return list;
}
}
}
return Enumerable.Empty<T>();
}
}
public class Animals
{
public IList<Bear> Bears { get; set; }
public IList<Pinguin> Pinguins { get; set; }
}
public class Bear
{
public string Name { get; set; }
}
public class Pinguin
{
public string Name { get; set; }
}
You are misunderstanding how to call propertyInfo.GetValue. The parameter you are passing to it should be the object whose property value you want to get. So in this case you are wanting the value of the property on animals so that line should be:
var list = (IEnumerable<T>) propertyInfo.GetValue(animals);
With this change your code is returning bears to me.
I think a dictionary would be better solution here instead of reflection. Out of the box a dictionary should be able to handle all of your scenarios and offer much better performance. If you want to encapsulate it in a class then it might look like this.
public interface IAnimal
{
string Name { get; set; }
}
public class Animals
{
private readonly ConcurrentDictionary<Type, IList<IAnimal>> AnimalDictionary;
public Animals(IList<IAnimal> animals)
{
this.AnimalDictionary = new ConcurrentDictionary<Type, IList<IAnimal>>();
this.Add(animals);
}
public Animals(IAnimal animal)
{
this.AnimalDictionary = new ConcurrentDictionary<Type, IList<IAnimal>>();
this.Add(animal);
}
public IList<IAnimal> Get<T>() where T : IAnimal
{
if (this.AnimalDictionary.ContainsKey(typeof(T)))
{
return this.AnimalDictionary[typeof(T)];
}
return (IList <IAnimal>)new List<T>();
}
public void Add(IList<IAnimal> animals)
{
foreach (IAnimal animal in animals)
{
this.Add(animal);
}
}
public void Add(IAnimal animal)
{
this.AnimalDictionary.AddOrUpdate(animal.GetType(),
new List<IAnimal>{animal},
(type, list) =>
{
list.Add(animal);
return list;
});
}
}
I've been working on a library to generate fake data using Faker.NET. The problem I'm having is that I don't know how to access an anonymous method that I'm passing to the constructor of my DataGenerator child classes.
The issue is that in order to create a list of generics I had to create base class DataGenerator but I cannot pull my Func<T> member up because that base class is not generic so no Tavailable. However, my DataGenerator<T> class does expose the Generator property which is my anonymous method but I haven't found a way to access it while iterating my list of data generators.
Any advice will be highly appreciated.
This is what I have so far:
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Guid EmpUid { get; set; }
}
// Define other methods and classes here
public abstract class DataGenerator
{
public abstract int GetWeight(string matchingProperty);
public abstract Type Type { get;}
}
public abstract class DataGenerator<T> : DataGenerator
{
public readonly string[] Tags;
public readonly Func<T> Generator;
protected DataGenerator(Func<T> generator, params string[] tags)
{
Tags = tags;
//How to access this?
Generator = generator;
}
public override int GetWeight(string matchingProperty)
{
int sum = (from tag in Tags
where matchingProperty.ToLowerInvariant().Contains(tag.ToLowerInvariant())
select 1).Sum();
return sum;
}
public override Type Type {
get { return typeof(T); }
}
}
public class StringDataGenerator : DataGenerator<string>
{
public StringDataGenerator(Func<string> generator, params string[] tags) : base(generator, tags)
{
}
}
public class GuidDataGenerator : DataGenerator<Guid>
{
public GuidDataGenerator(Func<Guid> generator, params string[] tags)
: base(generator, tags)
{
}
}
And I'm testing it here:
private static void Main(string[] args)
{
var dataGeneratorList = new List<DataGenerator>
{
new StringDataGenerator(Name.First, "first", "name"),
new StringDataGenerator(Name.Last, "last", "name"),
new GuidDataGenerator(Guid.NewGuid, "uid", "id")
};
var writeProperties = typeof (Employee).GetProperties().Where(p => p.CanWrite);
foreach (var property in writeProperties)
{
foreach (var dataGenerator in dataGeneratorList)
{
if (property.PropertyType == dataGenerator.Type)
{
var weigth = dataGenerator.GetWeight(property.Name);
//How to access generator here???
var testValue = dataGenerator.Generator.Invoke();
}
}
}
}
As you tagged, given your current setup, reflection is probably your only option.
var func = dataGenerator.GetType().GetField("Generator").GetValue(dataGenerator);
var testValue = func.GetType().GetMethod("Invoke").Invoke(func, null);
I'm not sure anyone could call this super nice, and it won't be super fast, but it's probably sufficient for anything you need fake data in, I suppose.
For good measure, here's it in action.
Your question is actually a bit more complicated than it may seem at face-value. A nice way of handling this if you only ever use it in object form is just to add an abstract Generate method to the base, non-generic class:
public abstract object Generate();
Then override it in your generic one:
public override object Generate()
{
return this.Generator();
}
Of course, this return an object, which isn't nice in a generic class. But at least it avoids reflection.
Another solution to avoid this reflection nonsense might be the use of covariance, although that will, unfortunately, break for value types, like Guid.
public interface IDataGenerator<out T>
{
int GetWeight(string matchingProperty);
Type Type { get;}
T Generate();
}
public abstract class DataGenerator<T> : IDataGenerator<T>
{
public readonly string[] Tags;
public readonly Func<T> Generator;
protected DataGenerator(Func<T> generator, params string[] tags)
{
Tags = tags;
//How to access this?
Generator = generator;
}
public T Generate(){
return this.Generator();
}
. . .
}
That then turns into a preferable,
private static void Main(string[] args)
{
var dataGeneratorList = new List<IDataGenerator<object>>
{
new StringDataGenerator(Name.First, "first", "name"),
new StringDataGenerator(Name.Last, "last", "name")
// But this line doesn't work
// new GuidDataGenerator(Guid.NewGuid, "uid", "id")
};
var writeProperties = typeof (Employee).GetProperties().Where(p => p.CanWrite);
foreach (var property in writeProperties)
{
foreach (var dataGenerator in dataGeneratorList)
{
if (property.PropertyType == dataGenerator.Type)
{
var weigth = dataGenerator.GetWeight(property.Name);
var testValue = dataGenerator.Generate();
}
}
}
}
I am merging some code bases into one and am trying to figure out a clever way to merge some slightly different generic objects into a list that builds some of the UI for filtering.
I have many Manager objects that produce and manage ResultSets that are built on top of some of the application base classes.
Any ideas would be great. I am trying not to refactor old deep code as much as possible.
CityManager is something like
ImAFilterSetManager<ImAFilterSetBase<CityBase>>
and ChainManger is something like
ImAFilterSetManager<ImAFilterSetBase<ChainBase>>
The Manager executes the Initialize and returns a ImAFilterSetBase and wires the handler.
Is there a way to cast to something like below?
ImAFilterSetManager<ImAFilterSetBase<object>>
Execution code
List<object> filters = new List<object>() {
new CityManager(),
new ChainManager(), }
//(XXXX as object fails)
foreach (ImAFilterSetManager<ImAFilterSetBase<XXXX>> filter in filters)
{
var newFilter = filter.Initialize(_Client);
filter.OnResultsChanged += filterResults_Handler;
}
It does seem if use dyanmic i can Initialize (or at least it compliles and runs, havent tried much else) but I'm a little worried that would be bad form or cause side effects.
foreach (dynamic filter in filters)
{
var newFilter = filter.Initialize(_Client);
}
Interfaces for reference ( generic I is a ImAFilterSetBase(CityBase) and generic C would be CityBase or ChainBase class )
public interface ImAFilterSetManager<I>
{
event EventHandler<ResultSetArgs> OnResultsChanged;
I Initialize(IClient client);
}
public interface ImAFilterSetBase<C>
{
string FilterName { get; set; }
List<C> Filter { get; set; }
}
In C#, Generic<A> and Generic<B> are not related, unless you make them related. Create another non-generic class (or interface) - FilterSetManager, and have all your ImAFilterSetManager<T> derive from that, or implement that.
Then you can have a List<FilterSetManager>.
You may think in the Liskov Substitution Principle (SOLID), so a good way is relate the objects via an interface:
//defines the contract
public interface IObjectBase {
//add signatures
}
class CityBase : IObjectBase /*, IAnotherBaseA */ {
//implementation
}
class ChainBase : IObjectBase /*, IAnotherBaseB */ {
//implementation
}
Now we are going to create a constraint for the ImAFilterSetBase and rename it to AFilterSetBase
public abstract class AFilterSetBase<T> where T : IObjectBase /*, new() */ {
public string FilterName { get; set; }
public IList<T> Filters { get; set; }
}
I am going to redefine the interface ImAFilterSetManager and rename it to IFilterSetManager
public interface IFilterSetManager {
event EventHandler<ResultSetArgs> OnResultsChanged;
AFilterSetBase<IObjectBase> Initialize(IClient client);
}
Now we can create the classes that implements IFilterSetManager:
public class CityManager : IFilterSetManager {
public AFilterSetBase<IObjectBase> Initialize(IClient client) {
//TODO: implementation
throw new NotImplementedException();
}
}
//other classes that implements IFilterSetManager
class ChainManager : IFilterSetManager {
public AFilterSetBase<IObjectBase> Initialize(IClient client) {
throw new NotImplementedException();
}
}
Finally, in the end-class we can create the list as follow:
static void Main() {
IClient _client;
//_client = new ...
var filters = new List<IFilterSetManager>() {
new CityManager(),
new ChainManager()
};
foreach (var item in filters) {
var newFilter = item.Initialize(_client);
}
}
IMPLEMENTATION
An example implementation for CityManager could be as follow:
class CityFilter : AFilterSetBase<IObjectBase> {
public CityFilter(string filterName) {
this.FilterName = filterName;
this.Filters = new List<IObjectBase>();
}
}
public class CityManager : IFilterSetManager {
public AFilterSetBase<IObjectBase> Initialize(IClient client) {
var item = new CityFilter("City Filters");
item.Filters.Add(new CityBase());
return item;
}
}
And then we can test it:
static void Main(string[] args) {
IClient _client;
_client = null;
var filters = new List<IFilterSetManager>() {
new CityManager(),
new ChainManager()
};
foreach (var item in filters) {
var newFilter = item.Initialize(_client);
System.Console.WriteLine("Filter name: " + newFilter.FilterName);
System.Console.WriteLine("Filters added: " + newFilter.Filters.Count);
}
System.Console.ReadLine();
}