Reputation: 13447
Related to: C# - Multiple generic types in one list and Access to property of inherited generic class
Please consider this code:
public abstract class Metadata
{
}
public class Metadata<T> : Metadata
{
public List<T> MyCollection{set; get;}
}
public class MetaDataCollection
{
public void DoSomeThing()
{
List<Metadata> metadataObjects = new List<Metadata>
{
new Metadata<int>() { MyCollection = new List<int>()},
new Metadata<bool>() { MyCollection = new List<bool>()},
new Metadata<double>() { MyCollection = new List<double>()},
};
foreach(vat item in metadataObjects)
{
item.MyCollection??????
}
}
}
in above code how I can access to MyCollection
property?
Thanks
Upvotes: 0
Views: 230
Reputation: 7440
You could fix it like List<>
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1 does it.
//use interfaces instead of abstract class
public interface IMetadata
{
List<object> MyCollection { get; set; }
}
public interface IMetadata<T>
{
List<T> MyCollection { get; set; }
}
//as List<> the List and List<> don't derive from each other but instead have a common interface the non-generic IList
public class Metadata : IMetadata
{
public List<object> MyCollection { get; set; }
}
//implement the generic and non-generic interface
public class Metadata<T> : IMetadata<T>, IMetadata
{
public List<T> MyCollection { get; set; }
//hide the non-generic interface member MyCollection
List<object> IMetadata.MyCollection { get { return this.MyCollection.Cast<object>().ToList(); } set { this.MyCollection = value.Cast<T>().ToList(); } }
}
public class MetaDataCollection
{
public void DoSomeThing()
{
//make a list of IMetadata
List<IMetadata> metadataObjects = new List<IMetadata>
{
new Metadata<int>() { MyCollection = new List<int>()},
new Metadata<bool>() { MyCollection = new List<bool>()},
new Metadata<double>() { MyCollection = new List<double>()},
};
foreach (var item in metadataObjects)
{
//item.MyCollection is now a List<object>
}
}
}
Upvotes: 1
Reputation: 5812
It's not elegant, but you could lookup the generic type argument and cast accordingly as below.
public class MetaDataCollection
{
public void DoSomeThing()
{
List<Metadata> metadataObjects = new List<Metadata>
{
new Metadata<int>() { MyCollection = new List<int>() { 1, 2, 3, 4} },
new Metadata<bool>() { MyCollection = new List<bool>() { true, false, false} },
new Metadata<double>() { MyCollection = new List<double>() { 1.5, 2.1 } },
};
Dictionary<Type, Action<Metadata>> actionLookup = new Dictionary<Type, Action<Metadata>>()
{
{ typeof(int), (meta) => Console.WriteLine(((Metadata<int>)meta).MyCollection[0]) },
{ typeof(bool), (meta) => Console.WriteLine(((Metadata<bool>)meta).MyCollection[0]) },
{ typeof(double), (meta) => Console.WriteLine(((Metadata<double>)meta).MyCollection[0]) }
};
foreach (var item in metadataObjects)
{
Type metaDataType = item.GetType().GenericTypeArguments.First();
actionLookup[metaDataType](item);
}
}
}
Upvotes: 1
Reputation: 1479
you must check your Item type and then cast it into a suitable MetaData:
public abstract class Metadata
{
}
public class Metadata<T> : Metadata
{
public List<T> MyCollection { set; get; }
}
public class MetaDataCollection
{
public void DoSomeThing()
{
List<Metadata> metadataObjects = new List<Metadata>
{
new Metadata<int>() { MyCollection = new List<int>()},
new Metadata<bool>() { MyCollection = new List<bool>()},
new Metadata<double>() { MyCollection = new List<double>()},
};
foreach (var item in metadataObjects)
{
if (item is Metadata<int>)
{
var intItem = item as Metadata<int>;
intItem.Add(10);
}
}
}
}
Upvotes: 0
Reputation: 6347
the code below breaks OOP ideology and rules, but it will achieve the aim. And be ware of exceptions
foreach(dynamic item in metadataObjects)
{
Console.WriteLine(item.MyCollection.Count);
}
Upvotes: 0