I have 3 classes Media,Image, Info. All three classes contain List of files implementing IResourceModel interface. These Media, Image & InfoFile are serialized and added to a Dictionary. I am looping on Dictionary, at runtime how can I cast these objects (Media, Image & InfoFile) to IResourceModel and fetch Files property.
public interface IResourceModel<T> {
T Files { get; set; }
}
class Media : IResourceModel<MediaFiles>
{
public MediaFiles Files { get; set; }
}
class Image : IResourceModel<ImagesFiles>
{
public ImagesFiles Files{ get; set; }
}
class InfoFiles : IResourceModel<InfoFiles>
{
public InfoFiles Files{ get; set; }
}
Dictionary<ResourceType, object> resourcesList = new Dictionary<ResourceType, object> {
{ ResourceType.Media,Media},
{ ResourceType.Image,Image},
{ ResourceType.InfoFiles , InfoFile}
};
The problem with your type hierarchy is that there is no IResourceModel. There is only a IResourceModel<T> where T is of a concrete type. With generic types, IResourceModel<A> and IResourceModel<B> are two discrete types for any different type argument A and B, that actually share nothing except the similar name. So you simply cannot cast Media, Image and InfoFiles into a common type (other than object) because there is no common type.
This is usually solved by introducing another non-generic type that is additionally implemented. For example, types implementing IEnumerable<T> also implement a non-generic IEnumerable to allow a non-generic iteration.
So your type hierarchy could look like this:
public interface IResourceModel
{
IFiles Files { get; }
}
public interface IResourceModel<T> : IResourceModel
{
new T Files { get; set; }
}
public class Media : IResourceModel<MediaFiles>
{
public MediaFiles Files { get; set; }
IFiles IResourceModel.Files => Files;
}
public class Image : IResourceModel<ImagesFiles>
{
public ImagesFiles Files { get; set; }
IFiles IResourceModel.Files => Files;
}
public class Info : IResourceModel<InfoFiles>
{
public InfoFiles Files { get; set; }
IFiles IResourceModel.Files => Files;
}
public interface IFiles {}
public class MediaFiles : IFiles { }
public class ImagesFiles : IFiles { }
public class InfoFiles : IFiles { }
Now you could cast your types into IResourceModel and access the Files property to iterate over all IFiles.
You will need to define a comment interface / class for you ImageFiles, InfoFiles and MediaFiles. Once example below.
interface IFiles
{
string myField { get; set; }
int myHash { get; set; }
}
class MediaFiles : IFiles
{
public string myField { get; set; }
public int myHash { get; set; }
}
Then you can iterate your dictionary by something like the following
Dictionary<ResourceType, IResourceModel<IFiles>> resourcesList = new Dictionary<ResourceType, IResourceModel<IFiles>> {
{ ResourceType.Media, new Media {Files = new MediaFiles {myHash = 20203, myField = "MediaFiles"} } }
};
foreach (KeyValuePair<ResourceType, IResourceModel<IFiles>> entry in resourcesList)
{
var files = entry.Value.Files;
var field = files.myField;
var hash = files.myHash;
}
Edit
Theoretically you can use dynamic instead of object to access what you want, i.e. File. But I would always do something like the above, to always have strong types enforced.
Edit 2
To cast generic interface, another interface implementation is needed.
public class Media : IResourceModel<MediaFiles>, IResourceModel<IFiles>
{
public MediaFiles Files { get; set; }
IFiles IResourceModel<IFiles>.Files
{
get { return Files; }
set { Files = (MediaFiles)value; } // <--- Cautious! Check type in production code.
}
}
Edit 3
Rethink of the fundamental problem you met, i.e. Why would you want a dictionary resourcesList? i.e. shouldn't your resource give you the type it belongs to, rather than you keep a mapping for them? This drives me to give the following complete re-implementation.
ResourceType is a property of Files.
Firstly, what you want to achieve at the end
var listOfFiles = new List<IFiles> // <-- List rather than Dictionary
{
new ImagesFiles(
new List<ImagesFile>
{
new ImagesFile {path = "C:\\wf.n"},
new ImagesFile {path = "C:\\wfz.n"}
}
),
new MediaFiles(
new List<MediaFile>
{
new MediaFile {path = "C:\\wf.jpg", foo = 1},
new MediaFile {path = "C:\\wfz.png", foo = 2}
}
)
};
foreach (var files in listOfFiles)
{
Console.WriteLine(files.resourceType); // <-- Gives Media / Image
var fileshash = files.GetHashCode();
foreach (IFile file in files.GetFiles())
{
var myPath = file.path;
var hash = file.GetHashCode();
}
}
Interface definitions
public interface IFile
{
string path { get; set; } // <--- GetHashCode doesn't need to be in here.
}
public interface IFiles : IEnumerable<IFile>
{
IEnumerable<IFile> GetFiles();
ResourceType resourceType { get; } // <-- Getter only here on the interface
}
public interface IFiles<out T> : IFiles
where T : IFile // <-- This will enforce the same file type in this collection
{
new IEnumerable<T> GetFiles();
}
Class definitions
public class ImageFile : IFile
{
public string path { get; set; }
public override int GetHashCode()
{
return path.GetHashCode();
}
}
public class ImageFiles : IFiles<ImageFile>
{
public ImageFiles(IEnumerable<ImageFile> files)
{
this.files = files.ToList();
}
public bool mySpecialProperty { get; set; } // <--- ImageFiles special, Not in Media nor Image
public ResourceType resourceType => ResourceType.Image;
private List<ImageFile> files;
public IEnumerable<IFile> GetFiles()
{
return files;
}
IEnumerable<ImageFile> IFiles<ImageFile>.GetFiles()
{
return files;
}
public IEnumerator<IFile> GetEnumerator()
{
return files.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override int GetHashCode()
{
return files.GetHashCode();
}
}
Related
I'd like to store LicenseInformations for multiple domains in my application.
The structure looks the following way:
public class LicenseData
{
// properties...
public List<LicenseDomain> Domains { get; set; }
// other properties...
}
public class LicenseDomain
{
// properties...
public object LicenseConfig { get; set; }
}
We have multiple domains with total different properties, but the license may contain multiple configurations..
For example:
{
"MaxValidUsers": 5
}
{
"Property": "xy"
"SubProperty": { "Foo" : "Bar"
}
}
The generation is no problem in any way..
But if I restore the informations from my signed json file I deserialize to object..
Which pattern / possiblity I have to work with Interfaces / Abstracts / that I can (RE)store generic informations here..
Right now I hack with:
JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(domain.LicenseConfig))
But I can't agree with myself.
So, based on the pieces of context I can grab, I would actually recommend having your LicenseConfig stored as a JSON string, which would give you the ability to do something like this:
public class LicenseDomain
{
// properties...
// Depending on how this is loaded,
// this property (or at least its setter) could be made private/protected/internal
public string LicenseConfigJson { get; set; }
public T LicenseConfig<T>() where T : BaseLicenseConfig
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
public void SaveLicenseConfig<T>(T config) where T : BaseLicenseConfig
{
if (config == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(config);
}
}
}
Or if each LicenseDomain can only have one type of LicenseConfig, you could make it a generic parameter to the class:
public class LicenseData
{
// properties...
public List<LicenseDomain<BaseLicenseConfig>> Domains { get; set; }
// other properties...
}
public class LicenseDomain<T> where T : BaseLicenseConfig
{
// properties...
// Depending on where this value comes from, you could do this a variety of ways,
//but this is just one
public string LicenseConfigJson { get; set; }
public T LicenseConfig
{
get
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
set
{
if (value == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(value);
}
}
}
}
public abstract class BaseLicenseConfig
{
}
public class LicConfig1 : BaseLicenseConfig
{
public int MaxValidUsers { get; set;}
}
public class LicConfig2 : BaseLicenseConfig
{
public string Property {get;set;}
public SubProp SubProperty {get;set;}
}
public class SubProp
{
public string Foo {get;set;}
}
In both cases, the BaseLicenseConfig class is strictly to enforce that everything in the domain list can come from a base class of some kind. If that's not important, you don't need the base class and can remove the where T : BaseLicenseConfig from LicenseDomain class.
I have a generic method that can be called with 2 different object types, TypeA or TypeB. TypeA and TypeB are essentially identical classes except in name only. I am trying to determine how to prevent from having to duplicate the Foreach loop code for each object type. Is this possible ? thanks.
public class TypeA
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
public class TypeB
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
private CsvExport GenerateExport<T>(IEnumerable<T> scores)
{
CsvExport export = new CsvExport();
List<TypeA> aList = null;
List<TypeB> bList = null;
Type type = scores.GetType();
if (type.FullName.Contains("TypeA"))
{
aList = scores as List<ObjectaModel>;
}
else if (type.FullName.Contains("TypeB"))
{
bList = scores as List<ObjectbModel>;
}
foreach (var dt in aList)
{
export.AddRow();
export["Name"] = dt.Name;
export["Department"] = dt.Department;
export["Total "] = dt.Total;
};
return export;
}
In this particular case I strongly suggest you delegate the hard work to the CsvHelper library which you can also obtain from Nuget and is used like this...
public void ExportToCsv<T>(string filename, ImmutableArray<T> objects)
{
using (var writer = File.CreateText(filename))
{
var csv = new CsvWriter(writer);
csv.WriteRecords(objects);
}
}
The more general answer to your question is that you must either have both classes inherit from a common class or interface or you would have to use reflection to look for an obtain the values of the named properties.
Using a common interface...
public interface IScore
{
int HiScore {get;}
}
public class ScrabbleScore : IScore
{
public int HiScore {get;set;}
}
public class PacManScore : IScore
{
public int HiScore {get;set;}
}
public void Export<T>(IEnumerable<T> scores) where T: IScore
{
foreach(var s in scores)
{
CvsExport["Hi score"]= s.HiScore;
}
}
Using reflection...
var CsvExport = new Dictionary<string,string>();
foreach(var o in scores)
{
//note that checking the type for each object enables you to have heterogenous lists if you want
var objectType= o.GetType();
foreach(var p in objectType.GetProperties())
{
var propertyName = p.Name;
CsvExport[propertyName] = p.GetValue(o).ToString();
}
}
I would treat the reflection solution as the least favoured of the three.
I need to instantiate a list-property where the generic type can be anything.
So my Main-method looks like this: (In real, ParsingObject<T> are objects I get from a service)
public static void Main()
{
Parser parser = new Parser();
parser.AddAnObject(
new ParsingObject<int>{PropertyName = "FirstProperty", Active=true, DefaultValue=1}
);
parser.AddAnObject(
new ParsingObject<bool>{PropertyName = "SecondProperty", Active=false, DefaultValue=false}
);
parser.Parse();
}
ParsingObject gets any type (I think only string, bool, int,...) as generic. Now in my parser I need to add this object into a List<ParsingObject<T>> like:
public class Parser
{
private readonly List<ParsingObject<T>> _listOfObjects = new List<ParsingObject<T>>();
public void AddAnObject<T>(ParsingObject<T> item)
{
_listOfObjects.Add(item);
}
public void Parse()
{
foreach(var item in _listOfObjects.Where(w=>Active))
{
DoSomething(item);
}
}
}
but I know, I cannot set T as generic argument when instantiating the list (compiler is crying..).
So I could solve this with using ArrayList - but then I can't access the properties of each object. (See the Parse()-method)
for completeness, here is my ParsingObject<T>-class:
public class ParsingObject<T>
{
public string PropertyName { get; set; }
public bool Active { get; set; }
public T DefaultValue { get; set; }
}
Any idea how I could solve this? I cannot modify the ParsingObject<T>-class.
Depending on what exactly is your end goal, maybe something like this would be sufficient:
public class ParsingObjectBase
{
public string PropertyName { get; set; }
public bool Active { get; set; }
public Type ValueType { get; protected set; }
public object DefVal { get; protected set; }
}
public class ParsingObject<T> : ParsingObjectBase
{
public object DefaultValue
{
get { return (T)DefVal; }
set { DefVal = value; }
}
public ParsingObject()
{
ValueType = typeof(T);
}
}
private readonly List<ParsingObjectBase> _listOfObjects = new List<ParsingObjectBase>();
public void AddAnObject<T>(ParsingObject<T> item)
{
_listOfObjects.Add(item);
}
public void Parse()
{
foreach(var item in _listOfObjects.Where(w=>w.Active))
{
DoSomething(item); //do what exactly?
}
}
You obviously can't do without casting either to concrete ParsingObject<T> or DefVal value in this case, but you have Type information stored in one place and have access to your specific properties. Maybe changing ValueType to some kind of enum would be easier to use with switch?
I often end up writing classes like this:
public class Animal
{
public string Colour { get; set; }
public int Weight { get; set; }
public Animal(Dog data)
{
this.Colour = data.Colour;
this.Weight = data.Weight;
}
public Animal(Cat data)
{
this.Colour = data.Colour;
this.Weight = data.Weight;
}
}
When you have lots of properties and types then you quickly end up with a lot of boiler plate code. Ideally in this situation I would just create an IAnimal interface and reference that. I'm currently in a situation where the Dog and Cat classes exist in a third party assembly and I can't modify them. The only solution that I can come up with is:
public class Animal
{
public string Colour { get; set; }
public int Weight { get; set; }
public Animal(Cat data){Init(data);}
public Animal(Dog data){Init(data);}
private void Init(dynamic data)
{
this.Colour = data.Colour;
this.Weight = data.Weight;
}
}
This works but I lose all type safety, is there a better solution than constructor injection?
Thanks,
Joe
EDIT: Here is a real world example. I have a third party library which returns 3 objects called:
GetPageByIdResult
GetPagesByParentIdResult
GetPagesByDateResult
(These are all auto generated classes from a service reference and the properties are pretty much identical)
Instead of dealing with these three objects I want to deal with a single PageData object or a collection of them.
You can have the logic in one common constructor that all the other constructors call:
public class Animal
{
public string Colour { get; set; }
public int Weight { get; set; }
public Animal(Dog data) : this (data.Colour, data.Weight)
{
}
public Animal(Cat data) : this (data.Colour, data.Weight)
{
}
private Animal(string colour, int weight)
{
this.Colour = colour;
this.Weight = weight;
}
}
This is pretty similar to your second solution but it doesn't lose type safety.
I'm currently in a situation where the Dog and Cat classes exist in a
third party assembly and I can't modify them
I'd suggest Automapper-based solution:
public static class AnimalFactory
{
public static Animal Create<T>(T source)
where T : class
{
Mapper.CreateMap<T, Animal>();
return Mapper.Map<Animal>(source);
}
}
Usage:
var catAnimal = AnimalFactory.Create(cat);
var dogAnimal = AnimalFactory.Create(dog);
Of course, you can provide a way to custom mapping configuration, if needed.
If you do not want to have the class littered like that you can try Extension methods?
public static Animal ToAnimal(this Dog item)
{
return new Animal() {Weight = item.Weight, Colour = item.Colour};
}
public static Animal ToAnimal(this Cat item)
{
return new Animal() {Weight = item.Weight, Colour = item.Colour};
}
try using json serializer's, with that we can ensure type safety.
public class Animal
{
public string Colour { get; set; }
public long Weight { get; set; }
public string Name { get; set; }
public Animal Create<T>(T anyType)
{
return GetObject<T, Animal>(anyType);
}
public K GetObject<T, K>(T type1)
{
try
{
var serialized = JsonConvert.SerializeObject(type1);
return JsonConvert.DeserializeObject<K>(serialized);
}
catch (Exception ex)
{
return default(K);
}
}
}
class Program
{
public static void Main(string[] args)
{
Animal obj = new Animal();
var animal = obj.Create(new { Colour = "Red", Weight = 100 });
//here you can pass any object, only same name properties will be initialized..
Console.WriteLine(animal.Colour + " : " + animal.Weight);
Console.ReadKey();
}
}
I have this c# code;
case "Cafe":
source.trendItem = new TrendingLocation<ITrendingCafe>();
break;
case "Pub":
source.trendItem = new TrendingLocation<ITrendingPub>();
break;
etc
a trendItem is defined like this;
public class TrendingItem<T> where T : ITrendingItem
{
public T trendItem { get; set; }
}
Then I have this;
public List<TrendingItem<ITrendingItem>> trendItems { get; set; }
Now for each item in the above trendItems i want to get the interfaces.
I tried using;
string g = fvm.trendItems[4].trendItem.GetType().GetInterfaces()[1].Name;
and
string g = typeof(TrendingLocation<>).GetInterfaces()[0].Name;
but neither of these lists the Generic interface such as ITrendingCafe, ITrendingRestaurant etc.
Is there a way I can get the name of the generic interface name?
You want to use the Type's GetGenericArguments method.
If I understand your structure, it will be something like:
Type[] typeArguments = fvm.trendItems[4].trendItem.GetType().GetGenericArguments();
foreach (Type tParam in typeArguments)
{
// Compare the type with the interface you are looking for.
}
I take it that ITrendingCafe is an interface that implements ITrendingItem. I wrote a quick program that takes and displays all of the interfaces that T Implements:
using System;
using System.Collections.Generic;
namespace TestConsoleApplication
{
public interface ITrendingItem
{
string ItemName { get; set; }
}
public interface ITrendingCafe : ITrendingItem
{
string CafeName { get; set; }
}
public class TrendingItem<T> where T : ITrendingItem
{
public T trendItem { get; set; }
}
public class Cafe : ITrendingCafe
{
public string ItemName { get; set; }
public string CafeName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var test = new List<TrendingItem<ITrendingItem>> { new TrendingItem<ITrendingItem> { trendItem = new Cafe() } };
foreach (var trendingItem in test[0].trendItem.GetType().GetInterfaces())
{
Console.Out.WriteLine(trendingItem.Name);
}
Console.ReadKey();
}
}
}
And here is the output:
As you can see, the interface is there. Just loop through and find the one you need!