I am quite new to the C# world and I apologize if the Question title not exactly match the content. But now to my Problem:
I have the following construct:
public interface IClass<TEnum>
{
Dictionary<TEnum, ISecondClass> dictionary { get; }
}
public abstract class ClassBase<TEnum> : IClass<TEnum>
{
public abstract Dictionary<TEnum, ISecondClass> dictionary { get; protected set; }
}
public class ConcreteClass : ClassBase<ConcreteClass.Concrete>
{
public override Dictionary<Concrete, ISecondClass> dictionary { get; protected set; }
public enum Concrete : ulong
{
}
}
public class OtherClass : ClassBase<OtherClass.Other>
{
public override Dictionary<Concrete, ISecondClass> dictionary { get; protected set; }
public enum Other : ulong
{
}
}
My goal is to instantiate all existing concrete classes based on it's enums, store all instances in a dictionary and later invoke some methods on each object.
I am not sure if this is even possible?
I am glad for any hint on this!
If I understand what you're trying to do, it sounds like a version of the Multiton Pattern. You may find it useful to research that.
From Wikipedia's example Multiton code:
class FooMultiton
{
private static readonly Dictionary<object, FooMultiton> _instances = new Dictionary<object, FooMultiton>();
private FooMultiton() {}
public static FooMultiton GetInstance(object key)
{
lock (_instances)
{
FooMultiton instance;
if (!_instances.TryGetValue(key, out instance))
{
instance = new FooMultiton();
_instances.Add(key, instance);
}
}
return instance;
}
}
This isn't directly pasteable into your class, but since you're looking for hints, I think it should point you in the right direction.
One word of caution about the above code: The method GetInstance will alter the dictionary if key isn't found. Personally, I associate the "Get" prefix with read-only methods. I'd either rename GetInstance or split it into two methods.
I'm not really sure what you mean by "instantiate all existing concrete classes based on it's enums", though. Can you clarify that?
Use Activator.CreateInstance() to create concrete classes' objects and store them into dictionary.
Pass your string classname from Enum and create dynamic class objects. Store them into Dictionary<Enum, ISecondClass>
myObject = (MyAbstractClass)Activator.CreateInstance("AssemblyName", "TypeName");
or
var type = Type.GetType("MyFullyQualifiedTypeName");
var myObject = (MyAbstractClass)Activator.CreateInstance(type);
While retrieving, based on your enum key, you know what type of instance value represents.
I don't understand a goal of the sample code, but you can write some thing like this:
public interface IClass
{
void MethodToDynamicInvoke();
}
public abstract class ClassBase<T>
: IClass
{
private Dictionary<Type, List<IClass>> instances = new Dictionary<Type, List<IClass>>();
public ClassBase()
{
List<IClass> list;
if (!instances.TryGetValue(typeof(T), out list))
{
list = new List<IClass>();
instances.Add(typeof(T), list);
}
list.Add(this);
}
public abstract void MethodToDynamicInvoke();
public void InvokeMetodOnClassesWithSameEnum()
{
List<IClass> list;
if (instances.TryGetValue(EnumType, out list))
{
foreach (var instance in list)
{
instance.MethodToDynamicInvoke();
}
}
}
}
public class ConcreteClass
: ClassBase<ConcreteClass.Concrete>
{
public ConcreteClass()
: base()
{
}
public override void MethodToDynamicInvoke()
{
throw new NotImplementedException();
}
public enum Concrete : ulong
{
}
}
public class OtherClass : ClassBase<OtherClass.Other>
{
public OtherClass()
: base()
{
}
public override void MethodToDynamicInvoke()
{
throw new NotImplementedException();
}
public enum Other : ulong
{
}
}
Related
I have a basic architecture for 'orders' in my game - each order has a basic data type and an 'order processor' which performs some action based on the given data. For example 'move to this point.'
I'd like to have a tidy system where I can simply pass in order data and the correct order processor will kick in, in such a way that I can easily add new OrderData/OrderProcessor classes without modifying other classes or messing around with enums or casting, so it seems like generics are the way to go.
This is the current code I have. I'm drawing a blank for how to draw a connection in the 'OrderService' class between the correct 'OrderProcessor' and 'IOrderData' pairs. See inside the OrderService<T> class for more information:
public interface IOrderData
{
}
// an order processor reads data from an IOrderData object until the data object says stop
public abstract class OrderProcessor<T> where T : IOrderData
{
protected T m_currentData;
public virtual void Start(T data)
{
m_currentData = data;
}
}
////////////////////////
public class MoveOrderData : IOrderData
{
public Vector3 Destination { get; private set; }
}
public class MoveOrderProcessor : OrderProcessor<MoveOrderData>
{
public override void Start(MoveOrderData data)
{
base.Start(data);
}
}
////////////////////////
public class OrderService<T> where T : IOrderData
{
private Dictionary<System.Type, OrderProcessor<T>> m_processors = new Dictionary<System.Type, OrderProcessor<T>>();
private OrderProcessor<T> m_currentProcessor;
public void GiveOrder(IOrderData data)
{
// this is the main problem: I'm not sure how to say "the given data is type 'MoveOrderData' so find out which
// OrderProcessor class handles those and pass it in". A simple switch statement and cast would suffice here
// but I'd like to automate the process
}
}
A possible solution here can be a making an OrderService class non-generic, because it can handle a different types of orders/order processors (according to comments). Then maintain a Dictionary<Type, Action<object>>, which wraps Action<object> to call Start method from OrderProcessor<T>.
I've extended the original code a little bit to show how it can work
public interface IOrderData
{
}
public class MoveOrderData : IOrderData
{
public Vector3 Destination { get; private set; }
}
public class AttackOrderData : IOrderData
{
}
public abstract class OrderProcessor<T> where T : IOrderData
{
protected T CurrentData { get; set; }
public virtual void Start(T data)
{
CurrentData = data;
}
}
public class MoveOrderProcessor : OrderProcessor<MoveOrderData>
{
}
public class AttackOrderProcessor : OrderProcessor<AttackOrderData>
{
}
public class OrderService
{
private readonly Dictionary<Type, Action<object>> m_processors = new Dictionary<Type, Action<object>>();
public OrderService()
{
AddProcessor(new MoveOrderProcessor());
AddProcessor(new AttackOrderProcessor());
}
private void AddProcessor<T>(OrderProcessor<T> processor) where T : IOrderData
{
var action = (Action<T>)processor.Start;
m_processors.Add(typeof(T), obj => action((T)obj));
}
public void GiveOrder(IOrderData data)
{
var action = m_processors[data.GetType()];
action?.Invoke(data);
}
}
It causes a downcasting obj => action((T)obj), but it shouldn't be a problem, since your data is constrained to IOrderData interface. Example of the usage
var service = new OrderService();
service.GiveOrder(new MoveOrderData());
service.GiveOrder(new AttackOrderData());
Is there an elegant (or any) way to achieve following in C#?
Let's have a class ItemBase (further derivable to Item1, Item2...), which does not allow direct instantiation (non-public construction) - to prevent user to create any 'untracked' instance of Item*.
Let's have a non-static class Manager, whose instances (multiple ones allowed) only can create and provide instances of Item* (because they keep track of produced instances and do some additional work).
Let's have an optional requirement: The Manager instances would like to manipulate non-public members of the managed Item instances (similar like the Manager would be a friend of Item*).
It would be nice if the Manager is not forced to be derivation of Item*.
It would be nice if there is as little reflection as possible.
Notes:
If possible, please consider this as a question raising from process of thinking how to implement particular problem solution in a best and elegant way. I would like it to be general and no, I don't have sources and yes, I have already tried some variants, but none of them satisfied my needs. Thank you.
As far as I know, there is no acceptable friend alternative (any of internal and InternalsVisibleToAttribute seems to be good), so the ItemBase just provides the 'special' (but public) modification methods and the user must be aware, these methods are not for him :o(
I like this solution, but I'm not able to invent, how to allow multiple Manager instances using it.
I think this might answer your problem :
public class ItemBase
{
protected ItemBase()
{
}
public void PublicMethod() { }
public int PublicProperty { get; set; }
}
public class Factory
{
private class PrivateItemBase : ItemBase
{
public void PrivateMethod() { }
public int PrivateProperty { get; set; }
}
public Factory(int id)
{
}
public IEnumerable<ItemBase> Items { get; private set; }
public ItemBase CreateItem()
{
PrivateItemBase rValue = new PrivateItemBase();
rValue.PrivateMethod();
rValue.PrivateProperty = 4;
return rValue;
}
}
Ok, giving up. If this might help to fully understand the purpose, there is the less bad solution I've (currently) ended up. Passing the creation functions is done via static constructors (which are not accessible by the users), unfortunately the ugly thing is their invocation...
Any idea how to make it better?
The item definitions:
namespace SpecialFactory
{
public enum ItemType
{
Item1,
Item2,
// ... Anyone deriving the Item* should add an item here
}
public abstract class ItemBase
{
public abstract ItemType Id {get;}
public static void RegisterAllCreators()
{
// Force static constructors invocation
var it = Item1.ClassId | Item2.ClassId; // Anyone deriving the Item* should ensure invocation of Manager.RegisterCreator
}
}
public class Item1 : ItemBase
{
static Item1()
{
Manager.RegisterCreator(ItemType.Item1, () => new Item1());
}
protected Item1()
{
}
public static ItemType ClassId => ItemType.Item1;
public override ItemType Id => ClassId;
}
public class Item2 : ItemBase
{
static Item2()
{
Manager.RegisterCreator(ItemType.Item2, () => new Item2());
}
protected Item2()
{
}
public static ItemType ClassId => ItemType.Item2;
public override ItemType Id => ClassId;
}
}
The manager:
namespace SpecialFactory
{
public class Manager
{
static Manager()
{
ItemBase.RegisterAllCreators();
}
protected static Dictionary<ItemType, Func<ItemBase>> creators = new Dictionary<ItemType, Func<ItemBase>>();
protected readonly List<ItemBase> managedItems = new List<ItemBase>();
protected ItemBase CreateItem(ItemType type)
{
ItemBase item = null;
if (creators.ContainsKey(type))
{
if ((item = creators[type]()) != null)
managedItems.Add(item);
}
return item;
}
public static void RegisterCreator(ItemType type, Func<ItemBase> creator)
{
if (!creators.ContainsKey(type))
creators[type] = creator;
}
public Manager()
{
}
public ItemBase Test(ItemType type)
{
// var notAllowed = new Item1();
var allowed = CreateItem(type);
return allowed;
}
}
}
The test:
namespace SpecialFactory
{
class Program
{
static void Main(string[] args)
{
var m1 = new Manager();
var m2 = new Manager();
var i1 = m1.Test(ItemType.Item1);
var i2 = m2.Test(ItemType.Item2);
}
}
}
I am writing an application for serialization of a generic List that holds any datatype.So I designed a base-DataType to fill the list with as follows:
public abstract class GenericObject<T> {
public string key;
public T value;
public GenericObject() { }
public GenericObject(string key, T value) : this() {
this.key = key;
this.value = value;
}
}
Furthermore there is a class GenericList which implements the IXmlSerializable-Interface to write a key-value pair as like this:
GenericObject<int> myInt = new GenericObject<int>("key", 3);
Which will produce the following XML:
<key>3</key>
The class-definition for the GenericList is more or less as follows:
public class GenericList<T> : IXmlSerializable {
List<T> objects;
// ...
}
So let´s assume we have a class Person that derives from GenericObject<string>(no matter how it looks like) and we want to fill the list with a couple of persons. The problem I have is defining a constraint on the generic type T of the GenericList-class so that only types are possible that derive from GenericObject. I already tried it by using public class GenericList<T> : IXmlSerializable where T : GenericObject<object> but that did not work because of the following compiler error:
Person' cannot be used as type parameter 'T' in the generic type or method 'GenericList<T>'. There is no implicit reference conversion from 'Person' to 'GenericObject<object>'
I also tried out leaving the where-clause empty, but then I have to check the type of T within the GenericList in order to get its key and value where I also failed with the following:
if (typeof(T).IsAssignableFrom(typeof(GenericObject<object>)))
which will always return false as T is of type Person and not GenericObject<object>.
May anyone have some suggestion how I can fill my list with a person?
You can use covariance. Since variant type parameters only can be declared in interfaces and delegates (not in class definitions), you also need to define an interface:
public interface IGenericObject<out T>
{
string Key { get; }
T Value { get; }
}
public abstract class GenericObject<T> : IGenericObject<T>
{
public string Key { get; set; }
public T Value { get; set; }
protected GenericObject() { }
protected GenericObject(string key, T value)
: this()
{
this.Key = key;
this.Value = value;
}
}
public class GenericList<TGenericObject> : IXmlSerializable
where TGenericObject : IGenericObject<object>
{
private readonly List<TGenericObject> _list = new List<TGenericObject>();
public void Add(TGenericObject item)
{
_list.Add(item);
}
public XmlSchema GetSchema()
{
// ...
}
public void ReadXml(XmlReader reader)
{
// ...
}
public void WriteXml(XmlWriter writer)
{
// ...
}
}
public class Person : GenericObject<string>
{
}
Now you can do this:
public class SomeClass
{
public void SomeMethod()
{
Person somePerson = new Person();
GenericList<IGenericObject<object>> listWithGenericsOfObject = new GenericList<IGenericObject<object>>();
listWithGenericsOfObject.Add(somePerson);
GenericList<IGenericObject<string>> listWithGenericsOfString = new GenericList<IGenericObject<string>>();
listWithGenericsOfString.Add(somePerson);
GenericList<Person> listWithGenericsOfPerson = new GenericList<Person>();
listWithGenericsOfPerson.Add(somePerson);
}
}
Now you don't need to check the type at runtime using IsAssignableFrom. However, in case you will need it, you should swap the types like this:
typeof(GenericObject<object>).IsAssignableFrom(typeof(T))
This is what I want to do in C# (within class Helper - without generic arguments),
List<AbstractClass<dynamic>> data;
public void Add<T>(AbstractClass<T> thing)
{
this.data.Add((AbstractClass<dynamic>) thing);
}
This helper class would take and work with AbstractClass<> objects and give back AbstractClass<> of specific generic type. AbstractClass<T> contains many functions which return T / take in T like public T Invoke().
For Helper class T cannot be known beforehand. The Add<T>(.. thing) function is not in a class of type T.
To be used like this in Helper class's functions,
foreach(var c in data.Where(x => ...))
{
// public T Invoke() { ... } function within AbstractClass<T>
var b = c.Invoke();
// logic
}
This also fails,
List<AbstractClass<object>> data;
public void Add<T>(AbstractClass<T> thing)
{
this.data.Add((AbstractClass<object>) thing);
}
Now I think I can have,
List<dynamic> data; // or List<object> data;
public void Add<T>(AbstractClass<T> thing)
{
this.data.Add(thing);
}
but I want the constraint that List named data has only elements of type like
ConcreteClass : AbstractClass<OtherClass>
So we would know that there is an public T Invoke() function but we do not know what it returns. This is helpful to avoid mistakes of say misspelling Invocke and only knowing at run-time.
I want to avoid casting to dynamic every time to invoke functions that give back generic type T
To do what you want to do you are going to need to use a Contravariant interface
public class Program
{
static void Main()
{
var m = new Helper();
m.Add(new ConcreteClass());
m.Process();
}
class Helper
{
List<IAbstractClass<OtherClassBase>> data = new List<IAbstractClass<OtherClassBase>>();
public void Add(IAbstractClass<OtherClassBase> thing)
{
this.data.Add(thing);
}
public void Process()
{
foreach(var c in data.Where(x => x.ShouldBeProcessed()))
{
var b = c.Invoke();
Console.WriteLine(b.Question);
var castData = b as OtherClass;
if (castData != null)
Console.WriteLine(castData.Answer);
}
}
}
public interface IAbstractClass<out T>
{
bool ShouldBeProcessed();
T Invoke();
}
abstract class AbstractClass<T> : IAbstractClass<T>
{
public bool ShouldBeProcessed()
{
return true;
}
public abstract T Invoke();
}
class ConcreteClass : AbstractClass<OtherClass>
{
public override OtherClass Invoke()
{
return new OtherClass();
}
}
class OtherClassBase
{
public string Question { get { return "What is the answer to life, universe, and everything?"; } }
}
class OtherClass : OtherClassBase
{
public int Answer { get { return 42; } }
}
}
You do not need to tell Add what kind of class you are passing it, all that matters is it derives from the type specified. You could do public void Add(IAbstractClass<object> thing) and every class would work, but Invoke() would only return objects inside the foreach loop.
You need to figure out what is the most derived class you want Invoke() to return and that is what you set as the type in the list.
Maybe this will work for you:
public class Program
{
static void Main()
{
var m1 = new Helper<OtherClass>();
m1.Add(new ConcreteClass());
var m2 = new Helper<int>();
m2.Add(new ConcreteClass2());
}
class Helper<T>
{
List<AbstractClass<T>> data = new List<AbstractClass<T>>();
public void Add<T1>(T1 thing) where T1 : AbstractClass<T>
{
this.data.Add(thing);
}
}
class AbstractClass<T> { }
class OtherClass { }
class ConcreteClass : AbstractClass<OtherClass> { }
class ConcreteClass2 : AbstractClass<int> { }
}
I have got a abstract class with an abstract method taking a parameter of the type of the implementing class. I can achieve this by generics like this:
abstract class Clazz<T>
{
public abstract void CopyFrom(Clazz<T> source);
}
class MyClass : Clazz<MyClass>
{
public override void CopyFrom(Clazz<MyClass>)
{
// implementation
}
}
Unfortunately I need in one of the implementing classes a list of Clazz<T> elements.
So how can I achieve this?
Of cause List<Clazz<T>> does not work.
List<Clazz<MyClass>> is too restrictive.
Removing the generics and the abstract method does work (my current solution), but this way I could forget to implement the CopyFrom() method in one of the implementing classes.
Edit: Here comes a more detailed example:
I've got an abstract class:
abstract class Clazz<T>
{
public abstract void CopyFrom(Clazz<T> source);
// ...
}
And a derived class:
class MyDerivedClass : Clazz<MyDerivedClass >
{
public string Text;
private readonly List<MySubClass> _list = new List<MySubClass>();
public override void CopyFrom(MyDerivedClass source)
{
Text = source.Text;
}
private List<Clazz> GetAllItems()
{
List<Clazz> list = new List<Clazz>();
list.Add(this);
list.AddRange(_list);
}
private class MySubClass : Clazz<MySubClass>
{
public int Number;
public override void CopyFrom(MySubClass source)
{
Number = source.Number;
}
}
}
There are several other deriving classes, the GetAllItems() Method is only needed in MyDerivedClass.
would this suffice? without more details it is hard to tell.
interface ICopyMaker
{
void CopyFrom(ICopyMaker source);
}
abstract class Clazz<T> : ICopyMaker
{
public abstract void CopyFrom(Clazz<T> source);
void ICopyMaker.CopyFrom(ICopyMaker source)
{
var src = source as Clazz<T>;
if (src == null) return; // know how to copy only from the instances of the same type
CopyFrom(src);
}
}
class MyClass : Clazz<MyClass>
{
private List<ICopyMaker> _list = new List<ICopyMaker>();
public override void CopyFrom(Clazz<MyClass> c)
{
//implementation
}
}
You can make the respective method generic, too, and introduce a constraint that takes T into account. If I understand well what you want to achieve, you can do this:
abstract class Clazz<T>
{
public abstract void CopyFrom(Clazz<T> source);
public abstract void ProcessList<TDescendant>(List<TDescendant> list)
where TDescendant : Clazz<T>;
}
class MyClass : Clazz<MyClass>
{
public override void CopyFrom(Clazz<MyClass> source)
{
// implementation
}
public override void ProcessList<TDescendant>(List<TDescendant> list)
{
// implementation
}
}
You can also easily include list processing in a descendant, like this:
class MyOtherClass : Clazz<MyOtherClass>
{
public override void CopyFrom(Clazz<MyOtherClass> source)
{
// implementation
}
// this list processing is inherited
public override void ProcessList<TDescendant>(List<TDescendant> list)
{
// implementation
}
// this list processing is specific to this descendant only
public void ProcessMyClassList<TDescendant>(List<TDescendant> list)
where TDescendant : Clazz<TMyClass>
{
// implementation
}
}
Then use can declare a descendant of MyClass, which in turn is a Clazz<T>, T being MyClass:
class MyDescendant : MyClass
{
}
The following works:
List<MyDescendant> list = new List<MyDescendant>();
new MyClass().ProcessList(list);
In case of MyOtherClass, the situation is a little bit different. ProcessMyClassList accepts a list of Clazz<T> or its descendants; however, not those related to MyOtherClass but to the good-ol' MyClass. This code works:
List<MyDescendant> list = new List<MyDescendant>();
new MyOtherClass().ProcessMyClassList(list); // this works
But the following won't compile:
List<MyOtherClass> list = new List<MyOtherClass>();
new MyOtherClass().ProcessList(list); // this works
new MyOtherClass().ProcessMyClassList(list); // this doesn't
Thank's everyone for your answers, but I think I have figured out a solution I can live with:
I will remove the generics and add a typecheck, like in the solution from anikiforov:
Abstract class:
abstract class Clazz
{
public abstract void CopyFrom(Clazz source);
}
And the derived class:
class MyDerivedClass : Clazz
{
public string Text;
private List<MyNestedClass> _list;
public override void CopyFrom(Clazz source)
{
var src = source as MyDerivedClass;
if (src == null) return;
Text = src.Text;
}
public List<Clazz> GetAllItems()
{
var list = new List<Clazz>();
list.Add(this);
list.AddRange(_list);
return list;
}
class MyNestedClass : Clazz
{
public int Number;
public override void CopyFrom(Clazz source)
{
var src = source as MyNestedClass;
if (src == null) return;
Number = src.Number;
}
}
}