[英]Implementing Interface Extending Properties (inheritance?)
我有一個必須解決的接口實現:這是一個示例:
interface ISettingsBase
{
string Name { get; set;}
DateTime TimeStamp { get; set; }
}
public class SettingsBase : ISettingsBase
{
public string Name { get; set; }
public DateTime TimeStamp { get; set; }
}
interface IWorkerBase
{
ISettingsBase Settings { get; set; }
}
public class WorkerBase: ISettingsBase
{
public ISettingsBase Settings { get; set; }
}
interface IExtendedSettings : ISettingsBase
{
string FilePath { get; set; }
}
interface IWorkerExtended : IWorkerBase
{
// This configuration property should respect those of
// the IWorkerBase and increase the features.
IExtendedSettings Settings { get; set; }
}
public class WorkerExtended : WorkerBase, IWorkerExtended
{
...
...
public IExtendedSettings Settings { get; set; }
}
問題是編譯器告訴我WorkerExtended中存在錯誤,並且我不尊重IWorkerBase.Settings接口的實現。 問題是我需要新的改進類還支持具有更多屬性的配置。
interface IWorkerBase
{
ISettingsBase Settings { get; set; }
}
interface IWorkerExtended : IWorkerBase
{
IExtendedSettings Settings { get; set; }
}
這已經成為問題,因為IWorkerExtended.Settings
將隱藏 IWorkerBase
所需的Settings
成員。 因此, IWorkerExtended
實現者仍將必須提供原始的Settings
成員(類型為ISettingsBase
),以可傳遞地實現IWorkerBase
。
編譯器會在這里警告您,因為此成員隱藏正在進行。 通常這樣做是錯誤的,因此您需要使用new
鍵盤來表示您願意這樣做:
interface IWorkerExtended : IWorkerBase
{
new IExtendedSettings Settings { get; set; }
}
注意,這對實現者沒有影響。 因此,在實現該接口時,您將必須提供兩個Settings
成員。 您可以通過顯式實現基本接口來做到這一點:
public class Worker : IWorkerExtended
{
public IExtendedSettings Settings { get; set; }
ISettingsBase IWorkerBase.Settings { get; set; }
}
這樣做的原因是很簡單: 里氏替換原則說,當IWorkerExtended
是的一個亞型IWorkerBase
,然后類型的任何對象IWorkerBase
可以通過類型的對象替換IWorkerExtended
。 現在考慮一下:
IWorkerBase baseWorker = GetExtendedWorker();
baseWorker.Settings = new SettingsBase(); // not extended
這只會工作,如果你可以在指定SettingsBase
來Settings
這是什么類型IWorkerBase
擔保(因為SettingsBase
是一個亞型ISettingsBase
)。 因此,為了使擴展工作程序可分配給基本工作程序類型,需要確保可以ISettingsBase
設置ISettingsBase
。 但是,如果只實施IWorkerExtended
,則可以將更具體的擴展設置分配給Settings
。
接口旨在隱藏實現細節,而不是告訴消費者“哦,這個家伙還有些其他字段”。
通常,強制轉換或類型檢查(如if (worker is IWorkerExtended)
表明您根本不需要接口。
我想說,在這種情況下,最好讓一堆worker
類實現一個空的IWorker
接口。
就像是:
public interface IWorker
{
}
public class SettingsBase
{
public string Name { get; set; }
public DateTime TimeStamp { get; set; }
}
public class ExtendedSettingsA : SettingsBase
{
public string FilePath { get; set; }
}
public class ExtendedSettingsB : SettingsBase
{
public string SomeOtherProp { get; set; }
}
public class WorkerBase : IWorker
{
public SettingsBase Settings { get; set; }
}
public class WorkerExtendedA : IWorker
{
public ExtendedSettingsA Settings { get; set; }
}
public class WorkerExtendedB : IWorker
{
public ExtendedSettingsB Settings { get; set; }
}
public class XmlLoader
{
public IWorker Load(string xml)
{
return null; // instance of WorkerBase or WorkerExtendedA or WorkerExtendedB
}
}
public class Consumer
{
public void Process(IWorker w)
{
if (w is WorkerBase)
{
WorkerBase wbase = w as WorkerBase;
string name = wbase.Settings.Name;
DateTime t = wbase.Settings.TimeStamp;
}
if (w is WorkerExtendedA)
{
WorkerExtendedA wa = w as WorkerExtendedA;
string name = wa.Settings.Name;
DateTime t = wa.Settings.TimeStamp;
string f = wa.Settings.FilePath;
}
if (w is WorkerExtendedB)
{
WorkerExtendedB wb = w as WorkerExtendedB;
string name = wb.Settings.Name;
DateTime t = wb.Settings.TimeStamp;
string other = wb.Settings.SomeOtherProp;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.