From generic Collection to non-generic collection - c#

I working within an older application (from 1.1 days) and there are many non-generic collections like:
[Serializable]
public class MyEntityList : CollectionBase
{
private int _virtualRecordCount;
public int VirtualRecordCount
{
get { return _virtualRecordCount; }
set { _virtualRecordCount = value; }
}
public MyEntityList()
{
}
public MyEntityList(MyEntity[] arr)
{
AddRange(arr);
}
public MyEntityList this[int index]
{
get { return (MyEntity)InnerList[index]; }
}
public void Add(MyEntity item)
{
InnerList.Add(item);
}
etc...
I've upgraded a layer of the application to use a generic Collection<T> for the return type. This layer is auto-generated and the class names are based upon the datasource table names. The business entity classes don't necessary line up either, but not so in this case. In this case, they match perfectly 1:1.
I tried mapping the collections like so:
Collection<MyEntityResponse> responses = GetMyEntityResponses();
AutoMapper.Mapper.CreateMap<MyEntityResponse, MyEntity>();
myEntityList = AutoMapper.Mapper.Map<MyEntityList>(responses);
The strangest thing... I thought that it might squawk at the use of CollectionBase, but I hit F5 anyway. To my suprise, no compiler error and no exception. WOOHOO!
However, later in the app it threw an exception complaining about a type conversion from MyEntityResponse to MyEntity when it tried to perform a foreach() on MyEntityList that was returned from Mapper.Map.
What happened is a new MyEntityList collection was returned but it was filled with MyEntityResponse objects. Huh?? The custom collection overrides the Add() method and specifies that the type must be of type MyEntity. I would expect it to blow up when attempting to add the wrong type to the collection, but it didn't seem to have any issues working with CollectionBase.
So my questions are, if the two types I'm trying to map match perfectly (property to property), and AutoMapper didn't have an issue with CollectionBase, why was it not able to map the enties? And why didn't it throw an exception instead of shoving the wrong type into the collection?
EDIT: I think I know why... because the non-generic collection doesn't have a known type associated with it, like the generic one does.
So, new question... how do I tell it to use MyEntity instead of MyEntityResponse ?

I think I found my answer: http://automapper.codeplex.com/wikipage?title=Lists%20and%20Arrays
For the non-generic enumerable types, only unmapped, assignable types
are supported, as AutoMapper will be unable to "guess" what types
you're trying to map. As shown in the example above, it's not
necessary to explicitly configure list types, only their member types.
As of release 0.2.0, no custom destination collection types are
supported.

Related

How to make list of dynamic list of generic class where T: struct?

I have a problem with making list of generic types where type argument is dynamic and struct. I think it'd be the best to just put example here.
public class Container
{
public List<B<dynamic>> someList = new List<B<dynamic>>();
public void AddToList(Type type)
{
var genericType = typeof(B<>);
var generic = genericType.MakeGenericType(type);
someList.Add(Activator.CreateInstance(generic) as B<dynamic>);
}
}
public class B<T> where T : struct
{
}
How can I get something like this to work without getting
error CS0453: The type 'dynamic' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'B'
Scenario is making system of items for my game. Game itself is in entity component system architecture so that everything in game is entity with some components(structs). I am making Item class which is ScriptableObject(sort of template which can be saved to xml file). I want every instance of Item to have this item specific components with item specific values in them. But the thing is I don't want each instance of this item to be the same but I would like this item to have some random values in specified range. I made it so that Item has list of ComponentSetup<>(B<> in my example) which takes Components(structs) and using reflection creates min/max values for each property Component has. In Item I need to access some functions of ComponentSetup so i need to make list of ComponentSetup<> but can't specify it as ComponentSetup< dynamic> becasue it takes only T where T : struct
I know this is thread necro, but for the benefit of the OP and anyone stumbling upon this same situation, I was trying to achieve the exact same thing as the OP.
Here's how I've solved and implemented this issue in my game:
Unity's file are MonoScripts, and as such, are not really valid types. When we drag scripts or game objects to the inspector, Unity uses reflection to extract useful types and methods from within the scripts.
MonoScript provides GetClass() which returns the class or struct defined within, but there was a bug reported about it returning error if the struct was defined within a namespace - in my case, it returned null:
https://issuetracker.unity3d.com/issues/monoscript-dot-getclass-returns-null-when-the-script-contains-a-struct-inside-a-namespace-or-an-interface-inside-a-namespace
So, for anyone trying to implement something similar, where you'd want to pass generic objects as custom scripts (component structs) or populate a list of components, cast the entry to MonoScript and call GetClass() avoiding defining the type within a namespace. Here's some pseduo-implementation for clarification:
// Assuming retrieving list of components from a List<UnityEngine.Object>
foreach (entry in componentList) {
Type ComponentType = (entry as MonoScript).GetClass();
var component = Activator.CreateInstance(ComponentType);
entity.AddComponent(component);
}
I don't know what you are going to achieve, but if you supply your generic class with this method, you could add its instances to dynamic list
public class B<T> where T : struct
{
public dynamic GetDynamic()
{
return this;
}
}

Properly using of the <T> type in generic methods in C#

So my real method is a lot different but I come down to this. It seems I don't fully understand how to handle the generic <T> type when I'm working with generic methods. My understanding is that we use generic methods when we want the same logic to work for different types, but we want the freedom to determine the exact type at run time. So it seems pretty natural to me that when I have a method like this :
internal static void ChangeCode<T>(Entity entity) where T : Entity
{
T tempEntity;
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
{
tempEntity = new SomeMoreSpecificEntity();
}
}
However if I try something like this I get an error Can not convert type T to SomeMoreSpecificEntity.
So where am I wrong. Isn't the idea to be able to do exactly this - declare a common type in compile time and cast to more specific type in run time?
You can't do that. Check following situation:
You have another class named SomeMoreSpecificEntity2 which is declared:
class SomeMoreSpecificEntity2 : Entity
{
}
You call your method ChangeCode<SomeMoreSpecificEntity2>, so T is SomeMoreSpecificEntity2, so tempEntity is SomeMoreSpecificEntity2 as well, but you're trying to assign SomeMoreSpecificEntity to it. That can't work.
You can try changing it to :
internal static void ChangeCode<T>(Entity entity) where T : Entity
{
Entity tempEntity;
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
{
tempEntity = new SomeMoreSpecificEntity();
}
}
It compiles.
No, the code you're trying to write is broken. For example, suppose I called:
ChangeCode<BananaEntity>(new SomeMoreSpecificEntity());
That would try to assign a reference of type SomeMoreSpecificEntity to a variable of type T, where T is BananaEntity.
It's not clear what you're trying to achieve, but that's why your current code won't compile. Given that you're not actually using T other than for a purpose for which it won't work your current code could be changed to make it a non-generic method, and just declare tempEntity as type Entity. Of course, that might not work for what you really want to do, but as you've only provided the non-working code, that's hard to determine :(
Three points about this line:
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
Did you actually mean entity to be of type T rather than type Entity? Currently it can be any entity
Did you really want to check the exact type? Normally you'd use is instead of calling GetType and comparing it directly with a type
Normally comparing types like this is a sign that you should consider a redesign. It's definitely not generic at this point, as it only copes with types that are hard-coded in it.
tempEntity = (T)(object)new SomeMoreSpecificEntity();
T can only cast with object

Force protobuf-net to ignore IEnumerable/ICollection interfaces

How can I get v2 of protobuf-net to ignore the fact that my class implements ICollection, IEnumerable, etc?
For this particular scenario, I only want the fields I have flagged as [ProtoMember] to be serialized.
I am currently in the process of converting from using protobuf-net v1 to using v2. I have a particular structure which is now serializing incorrectly because of the change. It looks something like the following:
[ProtoContract]
public class FileTree : ICollection<FilePath>, IEnumerable<FilePath>, IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged {
private FileTreeNode _Root;
[ProtoMember (1)]
public FileTreeNode Root {
get { return _Root; }
set { _Root = value; }
}
}
The FileTree class was written to collapse file paths like "C:\happy.txt" "C:\history.txt" into something more like
"C:\h"
└─── "appy.txt"
└─── "istory.txt"
The structure eliminates redundancy in the path strings. So, I really don't want the FileTree class being serialized via the IEnumerable functions because then it just gets stored as "C:\happy.txt", "C:\history.txt", etc. Right now, in the serialization of a FileTree object, each path is getting print out in full.
EDIT: One last thing I should mention -- I have an On_Deserialization function in FileTree which is tagged with [ProtoAfterDeserialization]. I put a breakpoint in the function, but it is not getting hit. Is this related to the way this class is being serialized?
[ProtoContract(IgnoreListHandling = true)]
public class FileTree : ICollection<FilePath> ...
{ ... }
should do it. I honestly don't think I've considered callbacks on lists, since they are handled so very different to entities, but with the above that should work. Let me know if it doesn't.
From the intellisense documentation:
Gets or sets a value indicating that this type should NOT be treated as a list, even if it has familiar list-like characteristics (enumerable, add, etc)

Interfaces no longer work when using custom collection class

I have created a class, MonitoredCollection<T>, that basically encapsulates/mimics List but allows me to fire events on certain calls.
Now however, whereever there is a parameter that takes a MonitoredCollection, where T is an Interface, I can no longer pass a MonitoredCollection<T> where T is a class that implements that interface, like I could with a List.
I always thought that interfaces were a language 'feature' and therefore I don't need to implement anything more to support this, so what have I missed?
EDIT: Sorry, I made a mistake in that question, as João correctly pointed out List never worked in this instance so the question is as it stands without that!
Suppose you have a MonitoredCollection<SomeObject> instance, and you want to treat it as a MonitoredCollection<ISomeInterface> instance where SomeObject does in fact implement ISomeInterface. This does not create any problems for retrieving items from the collection, since object of type SomeObject can be converted to the interface type ISomeInterface.
However, for all the methods on your collection which modify the collection, such as those that assign a new value to an index, or insert a new item into the collection, this cast has created a whole suite of issues. I'd assume your MonitoredCollection<SomeObject> instance would have a method such as Add(SomeObject obj), which would insert a new object into the collection. After the cast, the signature on this method would be Add(ISomeInterface obj). This seems to make sense, but not all ISomeInterface objects are NECESSARILY SomeObject instances.
Because the casted object will allow operations on the collection that the original object wouldn't allow, the runtime won't allow this cast. C# 4.0 introduced covariance and contravariance to explicitly state what is valid for casts of this type, you can look into them for trying to solve this issue. However, you're really only going to have luck with a read only version of your collection (think List<T>.AsReadOnly()).
Unfortunately, you can't do that with a list either. The compiler still cannot convert the types. You need to use a generic method. See code below:
class Test
{
void DoTest()
{
MonitoredList<IInterface> mlist1 = new MonitoredList<Inherited>(); //Error
MonitoredList<Inherited> mlist2 = new MonitoredList<Inherited>();
DoSomething1(mlist2); //Error converting MonitoredList<Inherited> to MonitoredList<IInterface>
MonitoredList<IInterface> list1 = new MonitoredList<Inherited>(); //Error
MonitoredList<Inherited> list2 = new MonitoredList<Inherited>();
DoSomething2(list2); //Error converting List<Inherited> to List<IInterface>
DoSomething3<Inherited>(mlist2); //Works fine
DoSomething3(mlist2); //<Inherited> is redundant
}
void DoSomething1(List<IInterface> list)
{ }
void DoSomething2(MonitoredList<IInterface> list)
{ }
//Generic method
void DoSomething3<T>(MonitoredList<T> list) where T : IInterface
{ }
}
interface IInterface { }
class Inherited : IInterface { }
class MonitoredList<T> { }

C# Pass Generics At Runtime

I have a method like the following:
public IEnumerable<T> GetControls<T>()
: where T : ControlBase
{
// removed.
}
I then created a class:
public class HandleBase<TOwner> : ControlBase
: TOwner
{
// Removed
}
I'd like to be able to call
GetControls<HandleBase<this.GetType()>>;
where it would use the type of THIS class to pass to the HandleBase. This would in essentially get all HandleBase that have an owner of THIS type.
How can I achieve this?
EDIT:
I'm using .NET 2.0 so solutions greater than 2.0 will not work.
The idea is to have ControlBase have a collection of other ControlBase for "children". Then they can be queried based on their type with GetControls<T>(). This would allow me to, for example, get all HandleBase for a Shape. Then I can take all of these and set Visible=false or do something else with them. Thus I can manipulate children of a specific type for a collection.
HandleBase<TOwner> requires the TOwner since it has a reference to the "owning type". So you can only add anything that extends HandleBase to a Shape. Make sense?
Thanks for all the help!
You can do this either by specifying a type at compile-time or by using reflection.
You can do it with reflection like this:
typeof(SomeClass).GetMethod("GetControls")
.MakeGenericMethod(typeof(HandleBase<>).MakeGenericType(GetType()))
.Invoke(someObject, null);
Note that it would return an object; you would not be able to cast it to IEnumerable<T> (Unless you know what T is at compile-time, in which case there's no point). You would be able to cast it to IEnumerable.
However, this is a bad idea.
There is probably a better solution for you; please provide more detail.
You can't. Generics is a compile-time feature. You would need to include the type as a non-generic parameter to the method, and pass it in there.
Note that type parameters are not variables. Therefore, you cannot use a variable in place of a type parameter.
You could, however, do this through reflection, or by using a special construct which is pretty limited but may solve your case:
public class MyClass<TSelf> where TSelf: MyClass<TSelf> {
public IEnumerable<T> GetControls<T>() where T: ControlBase {
// removed.
}
public void MyCall() {
GetControls<HandleBase<TSelf>>();
}
}
public class MyConcreteClass: MyClass<MyConcreteClass> {
}
Probably there is no way to do what you ask for. Extending your example:
X x = GetControls<HandleBase<this.GetType()>>;
What should the type X be here? However from other background information it seems that you need to get list of all controls of given type. You could do this for example in such way:
public IEnumerable<ControlBase> GetControls(Type type) {
//your logic here
}
Depending on your other usages and goals you might also want to return non-generic IEnumerable.
Since GetControls() returns an enumeration, you might find a way to filter the resulting enumeration with .OfType<T>, something like
List<T2> list = controlList.GetControls<T>().OfType<T2>().ToList();
You would need a generic constraint somehwere along the lines of
where T2 : T
This is specific to my implementation of this but I was able to solve this by creating a non-generic HandleBase first and then a generic HandleBase<TOwner> since the only place TOwner was being used was the property Owner.
Then when I can call GetControls<HandleBase> and get all HandleBase regardless of the Owner.
Thanks all for answers!

Categories