Recursive generic types - c#

Is it possible to define a generic type in C# that references itself?
E.g. I want to define a Dictionary<> that holds its type as TValue (for a hierarchy).
Dictionary<string, Dictionary<string, Dictionary<string, [...]>>>

Try:
class StringToDictionary : Dictionary<string, StringToDictionary> { }
Then you can write:
var stuff = new StringToDictionary
{
{ "Fruit", new StringToDictionary
{
{ "Apple", null },
{ "Banana", null },
{ "Lemon", new StringToDictionary { { "Sharp", null } } }
}
},
};
General principle for recursion: find some way to give a name to the recursive pattern, so it can refer to itself by name.

Another example would be generic tree
public class Tree<TDerived> where TDerived : Tree<TDerived>
{
public TDerived Parent { get; private set; }
public List<TDerived> Children { get; private set; }
public Tree(TDerived parent)
{
this.Parent = parent;
this.Children = new List<TDerived>();
if(parent!=null) { parent.Children.Add(this); }
}
public bool IsRoot { get { return Parent == null; } }
public bool IsLeaf { get { return Children.Count==0; } }
}
Now to use it
public class CoordSys : Tree<CoordSys>
{
CoordSys() : base(null) { }
CoordSys(CoordSys parent) : base(parent) { }
public double LocalPosition { get; set; }
public double GlobalPosition { get { return IsRoot?LocalPosition:Parent.GlobalPosition+LocalPosition; } }
public static CoordSys NewRootCoordinate() { return new CoordSys(); }
public CoordSys NewChildCoordinate(double localPos)
{
return new CoordSys(this) { LocalPosition = localPos };
}
}
static void Main()
{
// Make a coordinate tree:
//
// +--[C:50]
// [A:0]---[B:100]--+
// +--[D:80]
//
var A=CoordSys.NewRootCoordinate();
var B=A.NewChildCoordinate(100);
var C=B.NewChildCoordinate(50);
var D=B.NewChildCoordinate(80);
Debug.WriteLine(C.GlobalPosition); // 100+50 = 150
Debug.WriteLine(D.GlobalPosition); // 100+80 = 180
}
Note that you cannot directly instantiate Tree<TDerived>. It has to be a base class to the node class in the tree. Think class Node : Tree<Node> { }.

Related

How can I restrict who can make changes using interfaces?

I have a IHasTag interface, a TaggableItem class that implements IHasTag and a TaggingManager class which I want to make it the only one responsible for setting or clearing the Tags but I've been struggling all day trying to implement but with no luck.
How can I make this possible?
public class TaggableItem : TaggingManager.IHasTag
{
public string Tag { get; } // read only
}
public class TaggingManager
{
public interface IHasTag
{
string Tag { get; }
}
private List<IHasTag> _taggedItems = new();
public void TagItem(IHasTag item, string tag)
{
item.Tag = tag; // not working
_taggedItems.Add(item);
}
public void ClearAllTags()
{
foreach (var item in _taggedItems)
{
item.Tag = "": // not working
}
_taggedItems.Clear();
}
}
EDIT
I followed Thomas' suggestion and this is what I end up doing. I know it's not perfect, though. Thank you all for your advices.
public interface ITaggable
{
string? Tag { get; }
}
public interface ISelectable
{
bool IsSelected { get; }
}
public interface IItem : ITaggable, ISelectable
{
}
public class Item : IItem
{
protected Item() { }
public bool IsSelected { get; set; }
public string Tag { get; set; } = string.Empty;
// 'Item' will be created here returning IItem.
// So, unless you 'cast' it, you can't set 'Tag' or 'IsSelected'.
public static IItem CreateItem() => new Item();
}
public class SelectionManager
{
protected List<object> _items = new();
public void Select(ISelectable item)
{
if (item is Item selectable)
{
selectable.IsSelected = true;
_items.Add(item);
}
}
public void Unselect(ISelectable item)
{
if (item is Item selectable)
{
selectable.IsSelected = false;
_items.Remove(item);
}
}
}
public class TaggingManager
{
private List<object> _items = new();
public void Tag(ITaggable item, string tag)
{
if (item is Item taggable)
{
taggable.Tag = tag;
_items.Add(item);
}
}
public void Untag(ITaggable item)
{
if (item is Item taggable)
{
taggable.Tag = string.Empty;
_items.Remove(item);
}
}
}
My suggestion would be to have two interfaces for two purposes: reading and writing.
public interface IHasTag // interface for reading. Maybe IReadTag
{
string Tag { get; }
}
public interface ITagChange // interface for writing. Maybe IWriteTag
{
string Tag { set; }
}
public class TaggableItem : IHasTag, ITagChange // implement both
{
public string Tag { get; set; }
}
// Tagging manager gets write access (ITagChange)
public class TaggingManager
{
private List<ITagChange> _taggedItems = new ();
public void TagItem(ITagChange item, string tag)
{
item.Tag = tag;
_taggedItems.Add(item);
}
public void ClearAllTags()
{
foreach (var item in _taggedItems)
{
item.Tag = "";
}
_taggedItems.Clear();
}
}
// Everyone else has read access only (IHasTag)
class SomeoneElse
{
private List<IHasTag> _taggedItems = new ();
public void DoSomething(IHasTag item)
{
_taggedItems.Add(item);
var tag = item.Tag; // do something with the tag
}
}
class Instantiation
{
public void Main()
{
TaggableItem x = new TaggableItem();
TaggingManager m = new TaggingManager();
m.TagItem(x, "name");
SomeoneElse s = new SomeoneElse();
s.DoSomething(x);
}
}
One possible option is to move the "getter" also to the TagManager. Then the manager is responsible for the tags. The object itself does not even need to know about the tags.
You still can restrict this by exchanging object with an interface.
public class TagManager
{
private Dictionary<object, string> _tagedItems = new Dictionary<object, string>();
public bool HasTag(object item)
{
return _tagedItems.ContainsKey(item);
}
public string GetTag(object item)
{
return _tagedItems[item];
}
public void SetTag(object item, string tag)
{
if(!HasTag(item))
{
_tagedItems.Add(item, tag);
}
else
{
_tagedItems[item] = tag;
}
}
}
I don't think that this is really a answer to the OP, but one possible solution for the underlying problem.

Downcasting a List<AbstractClass> object to what the object actually is

I have a ParentClass. Two classes are inherit from it, FirstChildClass and SecondChildClass. A class MultipleValueTypes contains a Dictionary and a method that adds values to it. My intention is to be able to pass values of different classes, which inherit from the same abstract class to the value parameter of the Dictionary. Therefore, I initialize the dictionary with the value List<ParentClass> so that I would be able to add objects made with the child classes to the Dictionary. I can do this, but I cannot access them, therefore in the abstract class I create a way to tell them apart, a virtual method that both the children classes override to return their own class type.
I test the values they return against the enum itself and based on whether the condition is fulfilled, the object would be casted as what it is instead of a List<ParentClass>. Is this the wrong approach? Is this impossible?
I think it should work, because in my thinking the FirstObject and SecondObject are still objects of their respective classes, so casting should work and I should be able to access the overridden method.
What doesn't work: I cannot access the method that returns what type of class it is, because it only gets methods from the List<ParentClass>.
What I've tried so far: searching for a way to access the method, but I did not find any.
What I still need help with: everything mentioned above.
public abstract class ParentClass
{
public string Name { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
}
public class FirstChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public FirstChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the FirstChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public SecondChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the SecondChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public Dictionary<string, List<ParentClass>> ADictionary = new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if (!ADictionary.ContainsKey(Name))
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
class Program
{
static void Main(string[] args)
{
FirstChildClass FirstObject = new FirstChildClass("FirstObject");
SecondChildClass SecondObject = new SecondChildClass("SecondObject");
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if(TestDictionary.ADictionary["FirstObject"].TypeOfClass() == ParentClass.ChildClasses.FirstChildClass) ///List<ParentClass>' does not contain a definition for 'TypeOfClass' and no accessible extension method 'TypeOfClass' accepting a first argument of type 'List<ParentClass>' could be found (are you missing a using directive or an assembly reference?)
{
TestDictionary.ADictionary["FirstObject"] = (FirstChildClass)TestDictionary.ADictionary["FirstObject"]; ///Cannot convert type 'System.Collections.Generic.List<Dictionary.ParentClass>' to 'Dictionary.FirstChildClass
}
}
}
You forgot to use indexer of the list value of the key of the dictionary here:
==> TestDictionary.ADictionary["FirstObject"][0]
Here is your code now refactored too:
class Program
{
static void Main(string[] args)
{
var FirstObject = new FirstChildClass("FirstObject");
var SecondObject = new SecondChildClass("SecondObject");
FirstObject.ReturnMessage();
SecondObject.ReturnMessage();
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if ( TestDictionary.ADictionary["FirstObject"][0].TypeOfClass()
== ParentClass.ChildClasses.FirstChildClass )
{
TestDictionary.ADictionary["FirstObject"][0]
= (FirstChildClass)TestDictionary.ADictionary["FirstObject"][0];
}
Console.ReadKey();
}
}
public abstract class ParentClass
{
public string Name { get; set; }
public string RandomValue { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public virtual void ReturnMessage()
{
Console.WriteLine($"This is the {this.GetType().Name} instance");
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
}
public class FirstChildClass : ParentClass
{
public FirstChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
public SecondChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public readonly Dictionary<string, List<ParentClass>> ADictionary
= new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if ( !ADictionary.ContainsKey(Name) )
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
If the intention is to cast the whole list from List<ParentClass> to List<FirstChildClass> and List<SecondChildClass>, then Linq is your friend, just use the Cast function:
List<FirstChildClass> firstChildClasses = TestDictionary.ADictionary["FirstObject"]
.Cast<FirstChildClass>().ToList();
List<SecondChildClass> secondChildClasses = TestDictionary.ADictionary["SecondObject"]
.Cast<SecondChildClass>().ToList();

Cast generic collection item type

The following code illustrates a situation I'm having. The real code use different names and get values in other ways, but they match with what I need an answer. Specifically in lines 76-89 (the only lines I control) I need to extract a variable of type "ICollection" with the values and I don't like none of the used approaches. Is there another approach to do it without to create class "AbstractCollection"?
namespace ConsoleApp1
{
using System.Collections.Generic;
using System.Linq;
interface IEntity
{
string Id { get; }
string Name { get; }
}
class Entity : IEntity
{
public Entity(string id, string name)
{
Id = id;
Name = name;
}
public string Id { get; }
public string Name { get; }
}
interface ICollection<TGeneric>
{
IEnumerable<TGeneric> Items { get; }
}
class Collection<TGeneric> : ICollection<TGeneric> where TGeneric : Entity, IEntity
{
public IEnumerable<TGeneric> Items { get; set; }
}
class AbstractCollection<TConcrete, TAbstract> : ICollection<TAbstract> where TAbstract : class, IEntity
{
public AbstractCollection(ICollection<TConcrete> collection)
{
this._Items = new List<TAbstract>();
if (collection?.Items != null)
{
foreach (TConcrete concreteItem in collection.Items)
{
TAbstract abstractItem = concreteItem as TAbstract;
this._Items.Add(abstractItem);
}
}
}
public IEnumerable<TAbstract> Items
{
get { return this._Items; }
set { this._Items = value?.ToList(); }
}
private IList<TAbstract> _Items { get; set; }
}
class EntityCollection : Collection<Entity>
{
public EntityCollection()
{
var items = new List<Entity>()
{
new Entity("1", "Name1"),
new Entity("2", "Name2"),
new Entity("3", "Name3")
};
Items = items;
}
}
class Context
{
public Context()
{
var concreteItems = new EntityCollection();
// I can modify from this line to the end of the method but not any code before.
// I expected values in "list1" but is null.
var list1 = concreteItems as ICollection<IEntity>;
var list2 = concreteItems as ICollection<Entity>;
var abstractItems = new List<IEntity>();
foreach (Entity concreteItem in concreteItems.Items)
{
IEntity abstractItem = concreteItem as IEntity;
abstractItems.Add(abstractItem);
}
// Why "list3" is null?
var list3 = abstractItems as ICollection<IEntity>;
// I want to avoid class "AbstractCollection"
var list4 = new AbstractCollection<Entity, IEntity>(list2);
// Finally "list5" has value in the way I want it.
var list5 = list4 as ICollection<IEntity>;
}
}
class Program
{
static void Main(string[] args)
{
var context = new Context();
}
}
}
Covariance guides to the solution:
interface ICollection<out TGeneric>
{
IEnumerable<TGeneric> Items { get; }
}

Is using dictionary good practice to keep same classes?

I need to collect some classes and provide it by request to some parts of program. I have following code:
public interface ISameClass
{
int Value { get; set; }
void DoStuff();
}
public class SameClass : ISameClass
{
int Value { get; set; }
void DoStuff()
{
//Do something
}
}
public class SameClassProvider
{
private readonly Dictionary<string, ISameClass> _sameClasses;
public SameClassProvider(string parentDir)
{
_sameClasses = new Dictionary<string, ISameClass>
{
{ "Type1", new SameClass() },
{ "Type2", new SameClass() },
{ "Type3", new SameClass() }
};
}
public bool AddClass(string type, ISameClass class)
{
if (_sameClasses.ContainsKey(type) || class == null)
{
return false;
}
_nodes.Add(type, class);
return true;
}
public ISameClass GetClass(string type)
{
if (_sameClasses.TryGetValue(type, out var someClass))
{
return someClass;
}
}
}
Is using classes like SameClassProvider is good practice? Or i can refactor this something or replace with correct pattern? Tnx

How to mutate a list of custom objects in GraphQL for .NET

Using GraphQL for .NET, I would like to replace the collection of Foo with a new collection.
Given this server-side code:
public class Foo
{
public Foo(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class Root
{
public Foo[] Foos { get; private set; }
public Foo[] UpdateFoos(Foo[] foos)
{
Foos = foos;
return Foos;
}
}
public class MutationSchema : Schema
{
public MutationSchema()
{
Query = new MutationQuery();
Mutation = new MutationChange();
}
}
public class FooType : ObjectGraphType
{
public FooType()
{
Name = "IndividualFoo";
Field<StringGraphType>("name");
}
}
public class FoosType : ObjectGraphType<ListGraphType<FooType>>
{
public FoosType()
{
Name = "ListOfFoo";
Field<ListGraphType<FooType>>("foos");
}
}
public class FoosInput : InputObjectGraphType
{
public FoosInput()
{
Name = "InputForManyFoo";
Field<ListGraphType<FooInput>>("foos");
Field<ListGraphType<FooType>>("foosResult");
}
}
public class FooInput : InputObjectGraphType
{
public FooInput()
{
Name = "InputForSingleFoo";
Field<StringGraphType>("name");
}
}
public class MutationQuery : ObjectGraphType
{
public MutationQuery()
{
Name = "Query";
Field<FoosType>("queryAllFoos");
}
}
public class MutationChange : ObjectGraphType
{
public MutationChange()
{
Name = "Mutation";
Field<FoosInput>(
"updateAllFoos",
arguments: new QueryArguments(
new QueryArgument<FoosInput>
{
Name = "updateFoosQueryArgument"
}
),
resolve: context =>
{
var root = context.Source as Root;
var change = context.GetArgument<Foo[]>("updateFoosQueryArgument");
// TODO: update collection e.g. return root.UpdateFoos(change);
return change;
}
);
}
}
When I run the mutation query:
mutation M {
fooCollection: updateAllFoos(updateFoosQueryArgument: {
foos: [
{name: "First Foo"},
{name: "Second Foo"}
]}) {
foosResult
}
}
Then I get the following error:
{GraphQL.Validation.ValidationError: Cannot query field "foosResult" on type "InputForManyFoo". Did you mean "foosResult"?}
I'm using the latest version of GraphQL for .NET at the time of writing.
What am I missing?
Working Example: How to mutate a list of custom objects in GraphQL for .NET
My answer from Gitter.
Make an ObjectGraphType for the result. Notice that the “shape” of the object that is returned from resolve matches the “shape” of the graph type.
public class FoosResultType : ObjectGraphType
{
public FoosResultType()
{
Field<ListGraphType<FooType>>("foosResult");
}
}
public class FoosResult
{
public IEnumerable<Foo> FoosResult { get;set; }
}
public class MutationChange : ObjectGraphType
{
public MutationChange()
{
Name = "Mutation";
Field<FoosResultType>(
"updateAllFoos",
arguments: new QueryArguments(
new QueryArgument<ListGraphType<FooInput>>
{
Name = "updateFoosQueryArgument"
}
),
resolve: context =>
{
var root = context.Source as Root;
var change = context.GetArgument<List<Foo>>("updateFoosQueryArgument");
// TODO: update collection e.g. return root.UpdateFoos(change);
return new FoosResult { FoosResult = change };
}
);
}
}
And updated mutation:
mutation M {
fooCollection: updateAllFoos(updateFoosQueryArgument: [
{name: "First Foo"},
{name: "Second Foo"}
]) {
foosResult {
name
}
}
}

Categories