假设你有一个非泛型的Foo和泛型类Foo。在非泛型类中,您有一个非泛型FooBar类型的成员变量,同样在泛型类中有一个类型为FooBar的成员变量。
public class Foo
{
protected FooBar SomeVar;
public void DoSomething()
{
// Manipulate SomeVar here
}
}
public class Foo<T>: Foo where T: SomeObject
{
protected new FooBar<T> SomeVar;
}
此外,FooBar派生自FooBar,未在代码中显示。
假设非泛型类中有一个方法,它使用成员变量SomeVar进行一些数据操作。现在的问题是,如果通用类Foo被实例化,那么在非泛型类中实现的方法仅引用非泛型SomeVar,并且不了解泛型变量。
现在似乎唯一的办法就是覆盖泛型类中的DoSomething方法,这样可以让它知道泛型变量。
我想这种方法的问题是逻辑是从非泛型类到泛型类的重复。这个问题还有其他选择吗?
更新: 我已经更新了类以更好地解决我的问题:
public abstract class BaseObject
{
// Abstract class that handles how the object is loaded when querying database for an object
}
public class Name : BaseObject
{
public string FirstName {get;set;}
public string LastName {get;set;}
public Date DOB {get;set;}
}
public interface IData
{
List<string> SearchFields;
string timestamp;
Search search; // Search is a class that will query the database for a given object and because this is a non generic version, it'll bring back a list of base object
}
public interface IData<T> : IData, where T: BaseObject
{
Search<T> search; // Bring back a list of <T>
}
public class BrowseData: IData
{
Search search;
}
public class BrowseData<T>: BrowseData, IData<T> where T: BaseObject
{
Search<T> search;
}
public class BrowseBuilder
{
protected BrowseData Data;
public BrowseBuilder(BrowseData data)
{
Data = data;
}
public void DoRender()
{
// Using the data provided does the rendering
}
}
public class BrowseBuilder<T>: BrowseBuilder where T: BaseObject
{
protected new BrowseData<T> Data;
public BrowseBuilder(BrowseData<T> data)
{
Data = data;
}
}
我的问题是在非通用类BrowseBuilder中实现的方法DoRender,它使用非泛型数据/搜索来执行渲染,这将返回baseObject列表,而泛型版本将返回T列表。
也许我正在看这个错误,搜索应该是非泛型的,而且操作它的基本方法应该只返回baseObject列表。
答案 0 :(得分:1)
以下是使用界面的解决方案:
public interface IFooBar
{
// methods used for modifications
}
public class FooBar : IFooBar
{
// implement modification methods
}
public class FooBar<T> : IFooBar where T : SomeClass
{
// implement modification methods
}
public class Foo
{
protected IFooBar SomeVar;
public void DoSomething()
{
// Manipulate SomeVar via IFooBar interface here
}
}
public class Foo<T>: Foo where T: SomeObject
{
}
这可能看起来我只是在解决问题,但如果他们没有通用接口,你需要为FooBar
和FooBar<T>
实现不同的修改代码。
答案 1 :(得分:0)
它并不漂亮,但它可以完成工作:您可以在基类中定义一个事件,以在SomeVar
中公开值的更改,并相应地更新派生类中的属性。反之亦然。隐含地这意味着FooBar<T>
派生自FooBar
,但未在您的代码中显示。
public class Foo {
private FooBar _someVar;
protected FooBar SomeVar {
get { return _someVar; }
set {
if (_someVar != value) {
_someVar = value;
OnSomeVarUpdated();
}
}
}
protected event EventHandler SomeVarUpdated;
private void OnSomeVarUpdated() {
var someVarUpdated = SomeVarUpdate;
if (someVarUpdated != null) {
someVarUpdated(this, EventArgs.Empty);
}
}
public virtual void DoSomething() {
// Manipulate SomeVar here
var someVar = ....;
SomeVar = someVar;
}
}
public class Foo<T>: Foo where T: SomeObject {
public Foo() {
OnSomeVarUpdated += () => {
// Pull new value from base
SomeVar = (FooBar<T>)base.SomeVar;
};
}
private FooBar<T> _someVar;
protected new FooBar<T> SomeVar {
get { return _someVar; }
set {
if (_someVar != value) {
_someVar = value;
// Push new value to base
base.SomeVar = value;
}
}
}
}
答案 2 :(得分:0)
就个人而言,我会根据背景,情况以及您需要的方式选择不同的方法。对于所述问题,没有通用的解决方案。提供更多上下文详细信息将有助于提供更精确的答案。
你问了替代方案,这里是:
将逻辑移至FooBar
类。它直接或通过接口来决定。然后,您的Foo
将拥有DoSomething()
代理,该代理将直接在实际FooBar
个实例上调用实际方法。
如果FooBar
是简单的get / set类而没有上面的逻辑解决方案会破坏这种模式。为了克服这个问题,创建另一个用于FooBar
操作的类,它将实现所需的方法。
反转继承。而不是Foo<T> : Foo
使其成为Foo : Foo<SomeClass>
。但要注意 - 当类进一步继承时,事情可能会变得混乱。此解决方案也不适用于所有情况。这略微触及covariance/contravariance主题。
<强>脚注强>
另外,我建议不将protected FooBar SomeVar
中的Foo<T>
与其他成员进行对比,除非它对性能至关重要。相反,使用Foo<T>
中的属性和属性将仅返回基类的已转换值。通过这种方式,您最终只能在基类中使用一个成员。 FooBar.SomeVar
和FooBar<T>.SomeVar
中不可能有不同的值。