我有3个类媒体,图像,信息。所有三个类都包含实现IResourceModel接口的文件列表。这些Media,Image和InfoFile被序列化并添加到词典中。我正在循环使用Dictionary,在运行时如何将这些对象(Media,Image和InfoFile)转换为IResourceModel和fetch Files属性。
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}
};
您的类型层次结构的问题是没有IResourceModel
。只有IResourceModel<T>
T
是混凝土类型。对于泛型类型,IResourceModel<A>
和IResourceModel<B>
是任何不同类型参数A
和B
的两个离散类型,除了相似的名称之外实际上没有任何共享。因此,您根本无法将Media
,Image
和InfoFiles
转换为常见类型(除了对象),因为没有常见类型。
这通常通过引入另外实现的另一种非泛型类型来解决。例如,实现IEnumerable<T>
的类型也实现了非泛型IEnumerable
以允许非泛型迭代。
所以你的类型层次结构可能如下所示:
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 { }
现在你可以将你的类型转换为IResourceModel
并访问Files
属性来迭代所有IFiles
。
你需要为你定义一个注释接口/类ImageFiles
,InfoFiles
和MediaFiles
。一旦下面的例子。
interface IFiles
{
string myField { get; set; }
int myHash { get; set; }
}
class MediaFiles : IFiles
{
public string myField { get; set; }
public int myHash { get; set; }
}
然后,您可以通过以下内容迭代您的字典
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;
}
编辑
从理论上讲,你可以使用dynamic
而不是object
来访问你想要的东西,即File
。但我总是会像上面那样做,总是强制执行强类型。
编辑2
要转换通用接口,需要另一个接口实现。
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.
}
}
编辑3
重新思考你遇到的根本问题,即你为什么要一本字典resourcesList
?即你的资源不应该给你它所属的类型,而不是你为它们保留一个映射?这促使我给出以下完整的重新实现。
ResourceType
是Files
的财产。首先,你想在最后实现什么
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();
}
}
接口定义
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();
}
类定义
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();
}
}