区分两类

本文关键字:两类 | 更新日期: 2023-09-27 18:20:47

我有一个类FileRecord和类public class ZippedFileRecord : FileRecord,它们存储在具有所有FileRecords和ZippedFileRecords的SortedList mFiles中。我遇到的问题是,我需要一种方法来区分两者,每个ZippedFileRecord都有一个FileRecord和一个名为GetFileRecord()的方法,在该方法中,它解压缩与ZippedFileRecords关联的文件,并为其创建一个FileRecord

    public class ZippedFileRecord : FileRecord
    {
        FileInfo zipFileInfo; //FileName, FileCreationTime/Date
        public FileRecord myRecord = null;
        public FileRecord GetFileRecord()
        {
            if (myRecord == null)
            {
                //unzip and overwrite FileRecord
                UnZipFile();
                //return myRecord
                return myRecord;
                 }
                 else return myRecord;
            }
            ...
            ...
        } 

现在,使用这些FileRecords和ZippedFileRecords的代码部分是用户可以获取某个日期范围内的所有FileRecords,并获得屏幕上显示的信息的部分。由于ZippedFileRecords是Zipped文件的代表,因此必须首先对其进行解压缩。以下是用于查找要显示的文件的代码部分:

public GetFrames(DateTime desiredStartTime, DateTime  desiredEndTime)
{
    for(int fileIdx = mFiles.Values.Count-1; fileIdx >= 0; --fileIdx)
    {
        FileRecord rec = (FileRecord)mFiles.GetByIndex(fileIdx);
        if(rec.StartTime>= desiredStartTime && rec.EndTime<=desiredEndTime)
        {
            ...
        }
        else
        {
            ...
        }
    }
}

导致我出现问题的行是FileRecord rec = (FileRecord)mFiles.GetByIndex(fileIdx);。我有什么方法可以检查mFiles[fileIdx]是ZippedFileRecord还是FileRecord吗?因为如果我能做到这一点,我只能根据需要解压缩,而不是每次在屏幕上显示时都解压缩数百个文件,只有一两个文件真正符合用户的日期范围

区分两类

你可以做:

var zippedFileRecord = mFiles.GetByIndex(fileIdx) as ZippedFileRecord;
if (zippedFileRecord != null)
    ... do something with it

这样做会更干净:

foreach (var zippedFileRecord in mFiles.OfType<ZippedFileRecord>())
    ... do something with zippedFileRecord 

尽管通过向后浏览列表似乎你在做一些特别的事情,但如果是这样的话,这是行不通的。

但按类型过滤通常是一种代码味道。您可能应该向class FileRecord添加一个虚拟GetFileRecord()方法,以便在该类中适当地实现它。然后在class ZippedFileRecord中重写它,为该类做适当的事情。

然后,您只需在循环中调用GetFileRecord()方法,而无需担心底层类型。

从外观上看,GetFileRecord()class FileRecord中的实现将简单地为:

public virtual FileRecord GetFileRecord()
{
    return this;
}

class ZippedFileRecord中的实现与您已经编写的实现相同,但声明中添加了override

public override FileRecord GetFileRecord()
{
    ...

然后你可以这样使用它:

for(int fileIdx = mFiles.Values.Count-1; fileIdx >= 0; --fileIdx)
{
    FileRecord rec = ((FileRecord)mFiles.GetByIndex(fileIdx)).GetFileRecord();
    ...

最后一点:为什么不使用泛型SortedList<TKey, TValue>,以便使用强类型来避免强制转换?

您可以这样测试它:

if(mFiles.GetByIndex(fileIdx) is ZippedFileRecord)
{
   ...
}
else if(mFiles.GetByIndex(fileIdx) is FileRecord)
{
   ...
}

请注意,您需要按此顺序进行检查,因为ZippedFileRecord也是FileRecord,但不是相反。

使用is运算符-

if(rec is ZippedFileRecord)
{
  //Unzip logic here
}
else
{
}

使方法GetFileRecord() virtual在File记录类中,overrideZippedFileRecord

public class FileRecord
{
    public virtual FileRecord GetFileRecord()
    {
       return this;
    } 
} 
public class ZippedFileRecord : FileRecord
{
    public override FileRecord GetFileRecord()
    {
       // Unzip and retunr FileRecord instance.
    } 
}

这样你就不必担心类型了。这应该会起作用-

FileRecord rec = mFiles.GetByIndex(fileIdx).GetFileRecord();

您可以像这个一样使用is运算符

if (!(rec is ZippedFileRecord)) 
{
   // do your stuff in case rec is not ZippedFileRecord
}

您可以使用"is"检查对象是否为特定类型:

if (rec is ZippedFileRecord) {
    ...
}
else {
    ...
}

edit:有关更多选项,请参阅此问题。

就我个人而言,我想知道为什么ZippedFileRecord::GetFileRecord必须解压缩文件。由于您只需要元数据,我会重构该方法,以便在不解压缩文件的情况下设置元数据。然后,如果您确实需要文件数据本身,然后解压缩文件。