首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在泛型类C#中继承

在泛型类C#中继承
EN

Stack Overflow用户
提问于 2016-10-02 12:00:25
回答 2查看 189关注 0票数 1

我的大脑要爆炸了。)所以我想得到你的帮助。请考虑一下我的问题,就像关于程序员的难题一样。(实际上。也许这对你来说是个很简单的问题,但对我来说却不是。

需要创建对象数组。例如,列出T是类的列表。(我将在下面描述T类)。此外,还需要创建包含此数组的“容器”,以及用于处理该数组的一些方法。例如,Add(),Remove(int IndexToRemove)。类T必须有字段"Container",这样我们的数组中的每个元素都能够知道它包含在哪里,并且能够访问它的容器的字段和方法。注意,在这种情况下,类T应该有类型参数。事实上,事先还不知道使用哪种容器类型。让我们将这个类容器表示为A,类元素(类T)表示为AUnit。

代码:

代码语言:javascript
复制
class Program
{
  static void Main(string[] args)
  {
      A a = new A();
      a.Add();
      a.Units[0].SomeField +=100;    
      Console.ReadKey();
  }
}


class A
{
    public List<AUnit> Units;

    public A()//ctor
    {
        Units = new List<AUnit>();
    }
    public void Add()
    {
        this.Units.Add(new AUnit(this));
    }
}
class AUnit
{
    public int SomeField;
    public A Container;
    public string Name { get; private set; }
    public AUnit(A container)
    {
        this.SomeField = 43;
        this.Container = container;
        this.Name = "Default";
    }
}

当然,公共字段应该受到保护或者是私有的,但是让我们稍后再考虑一下。您可以问“为什么我们在AUnit中创建公共容器字段”?我们创建字段公共字符串名{get;私有集;}(实际上是属性,但没关系)。此外,我们还希望能够更改该字段的值,例如,方法类AUnit公共bool重命名(String newName)();。该方法的主要思想是只在数组中没有一个元素(公共列表单元;)具有与newName相同的名称时才更改Name字段。但是要实现这一点,重命名方法必须能够访问当前使用的所有名称。这就是为什么我们需要容器字段。

扩展版本AUnit代码

代码语言:javascript
复制
class AUnit
{
    public int SomeField;
    public A Container;
    public string Name { get; private set; }
    public AUnit(A container)
    {
        this.SomeField = 43;
        this.Container = container;
        this.Name = "Default";
    }
    public bool Rename(String newName)
    {
        Boolean res = true;
        foreach (AUnit unt in this.Container.Units)
        {
            if (unt.Name == newName)
            {
                res = false;
                break;
            }
        }
        if (res) this.Name = String.Copy(newName);
        return res;
    }
}

好的。如果你还在读,让我们继续。现在我们需要创建类B和类BUnit,它们非常类似于类A和类A单元。最后,这个难题的主要问题是我们如何才能做到这一点?当然,我可以CopyPaste和位修改A和AUnit并创建这段代码。

代码语言:javascript
复制
class B
{
    public List<BUnit> Units; //Only Type Changing

    public B()//ctor Name changing...
    {
        Units = new List<BUnit>();//Only Type Changing
    }
    public void Add()
    {
        this.Units.Add(new BUnit(this));//Only Type Changing
    }
}
class BUnit
{
    public int SomeField;
    public B Container;//Only Type Changing
    public string Name { get; private set; }
    public A a; //NEW FIELD IS ADDED (just one)

    public BUnit(B container) //Ctor Name and arguments type changing 
    {
        this.SomeField = 43;
        this.Container = container;
        this.Name = "Default";

        this.a=new A(); //New ROW (just one)
    }
    public bool Rename(String newName)
    {
        Boolean res = true;
        foreach (BUnit unt in this.Container.Units) //Only Type Changing
        {
            if (unt.Name == newName)
            {
                res = false;
                break;
            }
        }
        if (res) this.Name = String.Copy(newName);
        return res;
    }
}

我可以用这种方法来使用这个类。

代码语言:javascript
复制
static void Main(string[] args)
{
    B b = new B();
    b.Add();
    b.Units[0].a.Add();
    b.Units[0].a.Units[0].SomeField += 100;
    bool res= b.Units[0].a.Units[0].Rename("1");
    res = b.Units[0].a.Units[0].Rename("1");

    Console.ReadKey();
}

这种结构可以用来创建“非同质树”。

救命,我需要有人帮忙,只是没有人…。甲壳虫乐队

我使用BUnit创建了B和CopyPaste。但是如何使用“宏定义”或“泛型”、继承或其他优雅风格的东西来完成呢?(C#语言)我认为没有理由描述我所有失败的尝试和子问题。话题已经太长了。:)

如果你还在读,明白我想问什么,那就谢谢你了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-10-02 12:11:38

您需要实现一个基本类型,让我们称它为UnitBase,具有所有公共功能。我会按照以下方式构造您的代码:

  1. 为容器创建一个接口,这样您就可以将实现更改为更高性能的解决方案,而无需修改要添加到容器中的元素。 公共接口IContainer {Q Add(),其中q: UnitBase,新();IEnumerable单元{ get;}
  2. 按照1中所述的想法,为什么不让搜索逻辑属于容器呢?这更有意义,因为它将主要取决于容器是如何实现的: 公共接口IContainer {Q(),其中Q: UnitBase,新();IEnumerable单元{ get;} bool包含(字符串名称);} IContainer的具体实现可以是: 公共类容器: IContainer { public容器(){ List =新列表();}私有列表列表;公共Q Add(),其中Q: UnitBase,新(){ var newItem = Activator.CreateInstance();newItem.SetContainer(this);list.Add(newItem);返回newItem;}公共单元=> list.Select(i => i);公共bool包含(字符串名称) => Units.Any(单元=> unit.Name ==名称);}
  3. AUnitBUnit类型创建一个基类,凝聚所有公共功能: 公共抽象类UnitBase {受保护的UnitBase() }公共IContainer容器{ get;私有集;} public int SomeField;公共字符串名称{ get;私有集;}公共空SetContainer(IContainer容器){容器=容器;} public bool重命名( string newName) { if (Container.Contains(newName))返回false;this.Name = newName;//不需要使用String.Copy返回true;}
  4. 实现您的具体类型: 公共类BUnit : UnitBase { public int SpecificBProperty { get;私有集;} public BUnit() {}

这种方法的缺点?嗯,容器必须是<UnitBase>类型,我已经删除了泛型类型,因为在这种特殊情况下,它并没有做太多事情,因为它在泛型类型中是不变的。

此外,请记住,类型系统中没有任何东西可以避免以下情况:

代码语言:javascript
复制
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();

如果在同一个容器中有两个不同的类型不是一个选项,那么整个设置就会崩溃。这个问题在以前的解决方案中也存在,所以这不是什么新问题,我只是忘了指出它。

票数 3
EN

Stack Overflow用户

发布于 2016-10-03 14:17:59

InBetween,我非常感谢你的建议。事实上,我不能说我完全理解你的答案,但是我用你的想法做了我想做的事情。

看来我的变体很好用。不过,我想听听您(和每个人)对下面描述的代码的看法。这种结构的主要目标是创建非同质树。你能从这边估计一下吗。

首先。我们需要为两个类创建接口。我们描述了所有的“交叉使用”功能。

代码语言:javascript
复制
public interface IUnit<T>
{
    string Name { get;}
    void SetContainer(T t);
    bool Rename(String newName);   
}
public interface IContainer
{
   bool IsNameBusy(String newName);
   int Count { get; }
}

下一首。为将来的继承创建单元类的基。我们将在这个容器库的继承者方法中使用,因此我们需要通用属性和IUnit接口。

代码语言:javascript
复制
 class UnitBase<T> : IUnit<T> where T : IContainer

不幸的是,我还不知道如何解决构造器参数的问题。所以我才用方法

代码语言:javascript
复制
 SetContainer(T container).

代码:UnitBase

代码语言:javascript
复制
class UnitBase<T> : IUnit<T> where T : IContainer
{
    protected T Container;
    public string Name { get; private set; }
    public UnitBase()
    {
        this.Name = "Default";
    }
    public void SetContainer(T container)
    {
        this.Container = container;
    }
    public bool Rename(String newName)
    {
        bool res = Container.IsNameBusy(newName);
        if (!res) this.Name = String.Copy(newName);
        return !res;
    }
}

下一首。创建ContainerBase

ContainerBase应:

( 1)具有IContainer接口。

2)了解其中将包含哪些内容:

代码语言:javascript
复制
 ... where U : IUnit<C>, new() 

3)和.有关于它本身的信息。我们需要将这些信息作为参数传递给SetContainer()方法。

代码ContainerBase:

代码语言:javascript
复制
class ContainerBase<U, C> : IContainer //U - Unit Class.  C-Container Class
    where U : IUnit<C>, new()
    where C : ContainerBase<U, C>
{
    protected List<U> Units;
    public U this[int index] { get { return Units[index]; } }
    public ContainerBase()//ctor
    {
        this.Units = new List<U>();
    }
    public void Add()
    {
        this.Units.Add(new U());
        this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
    }
    public bool IsNameBusy(String newName)
    {
        bool res = false;
        foreach (var unt in this.Units)
        {
            if (unt.Name == newName)
            {
                res = true;
                break;
            }
        }
        return res;
    }
    public int Count { get { return this.Units.Count; } }
}

Cast ((TContainer)(这个))可能有点奇怪。但是使用ContainerBase时,我们应该始终使用NewInheritorContainer。所以这个演员就是什么都不做…看上去..。

终于来了。这个类可以像在这个例子中一样使用。

代码语言:javascript
复制
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}

class SheetUnit : UnitBase<SheetContainer>
{
    public CellContainer Cells;
    public PictureContainer Pictures;
    public SheetUnit()
    {
        this.Cells = new CellContainer();
        this.Pictures = new PictureContainer();
    }
}

class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }

class CellUnit : UnitBase<CellContainer>
{
    public string ValuePr;//Private Field
    private const string ValuePrDefault = "Default";  
    public string Value//Property for Value
    {
        //All below are Just For Example.
        get
        {
            return this.ValuePr;
        }
        set
        {
            if (String.IsNullOrEmpty(value))
            {
                this.ValuePr = ValuePrDefault;
            }
            else
            {
                this.ValuePr = String.Copy(value);
            }
        }
    }
    public CellUnit()
    {
        this.ValuePr = ValuePrDefault;
    }
}

class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }

class PictureUnit : UnitBase<PictureContainer>
{
    public int[,] Pixels{get;private set;}
    public PictureUnit()
    {
        this.Pixels=new int[,]{{10,20,30},{11,12,13}};
    }
    public int GetSizeX()
    {
        return this.Pixels.GetLength(1);
    }
    public int GetSizeY()
    {
        return this.Pixels.GetLength(0);
    }
    public bool LoadFromFile(string path)
    {
        return false;
    }
}
static void Main(string[] args)
    {
        SheetContainer Sheets = new SheetContainer();
        Sheets.Add();
        Sheets.Add();
        Sheets.Add();
        Sheets[0].Pictures.Add();
        Sheets[1].Cells.Add();
        Sheets[2].Pictures.Add();
        Sheets[2].Cells.Add();


        Sheets[2].Cells[0].Value = "FirstTest";
        bool res= Sheets[0].Rename("First");//res=true
        res=Sheets[2].Rename("First");//res =false

        int res2 = Sheets.Count;
        res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
        res2 = Sheets[2].Pictures.Count;//1
        res2 = Sheets[1].Pictures.Count;//0
        res2 = Sheets[0].Pictures[0].GetSizeX();//3
        Console.ReadKey();
    }

看上去像是我想要的。但我没有把它装满。让我再次感谢你,InBetween

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39816772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档