在通用/非通用情况下操纵类成员

时间:2014-03-10 13:52:17

标签: c# generics inheritance

假设你有一个非泛型的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列表。

3 个答案:

答案 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
{

}

这可能看起来我只是在解决问题,但如果他们没有通用接口,你需要为FooBarFooBar<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.SomeVarFooBar<T>.SomeVar中不可能有不同的值。