tags:

views:

98

answers:

4

Is there any way to generify this two classes?

class Tag1{
  public Tag1 Parent{get;set;}
}

class Tag2{
  public Tag2 Parent{get;set;}
}

So I will have:

class Tag1 : Tag{}

class Tag2 : Tag{}

Seems no, but possible that I missed something global.

Thanks to Jon, I ended with the following solution:

class Tag1 : Tag<T> {
   public T Parent {get;set;}

  public T AddNew(){
      return new T(){Parent = (T)this;} // This works
  }
}
A: 

Heh... my first thought was this:

public class ParentizedClass<T>
{
   public T Parent {get; set;}
}

But then I thought... "no, that can't work."

I don't believe it's possible.

Hmm... working on it some more, you could use an interface:

public interface ParentizedClass<T>
{
   public T Parent {get; set;}
}

And then have the class implement the interface using itself as the base class:

public class MyClass : ParentizedClass<MyClass>
{
    public MyClass Parent {get; set;}
}

But I can't check that for validity at the moment.

Randolpho
Of course it can - why couldn't it?
Jon Skeet
Because you can't declare an instance of it.var obj = new ParentizedClass<ParentizedClass<ParentizedClass<...>>>();
Randolpho
Because the parent is not the same type as the original class. The parent is of type T while the original class is of type ParentizedClass<T>. He wants the parent to be the same type as the original class, if I'm understanding it correctly.
Alex319
Right - it doesn't answer the question, but the code presented was valid.
Jon Skeet
A: 

How about:

class Tag<T>
{
    public Tag<T> Parent{get; set;}
}

?

Alex319
+5  A: 

Okay, slightly messier than before, and the subclass needs to do a bit more work, but...

public abstract class SelfRef<T> where T : SelfRef<T>
{
    private readonly Func<T> childFactory;

    public T Parent { get; set; }

    protected SelfRef(Func<T> childFactory)
    {
        this.childFactory = childFactory;
    }

    public T AddNew()
    {
       return childFactory();
    }
}

public sealed class Ref1 : SelfRef<Ref1>
{
    public Ref1()
        : base(() => new Ref1 { Parent = this })
    {            
    }
}

I think that meets the requirements. Note that you'll always have trouble implementing a hierarchy more than one level deep under SelfRef however you do it, so don't bother :)

You could potentially make the child factory take the new parent. Basically the type relationship you really want - that T = (the same type deriving from SelfRef<T>) - can't be expressed in .NET generics, which is why you have a slight mess.

Jon Skeet
How would you instantiate that with a self-reference? First<First<First<...>, Second<...>>, Second<Second<Second<...>>>>?
jrista
You'd use the subclass.
Jon Skeet
jrista I do not need instantiation, but the problem with this solution is that Tagged<T> cannnot create instances of the same type. I forgot to add this requirment to questtion.
Mike Chaliy
One sec I will try.
Mike Chaliy
Damn, evening, need coffee! Thanks Jon!
Mike Chaliy
Jon, I found why this want work for me before. I need "T Parent"....
Mike Chaliy
Ah yes. Okay - will take a look later. I suspect the subclass needs to pass in a function to create a new instance appropriately.
Jon Skeet
jrista
Yep, this fully resolved my problem. I ended with simple casting in Add method. So Parent = (T)this. And this works for me. Of course, solution with delegate looks great, but cast is just simplier :).
Mike Chaliy
@Mike: Yup - the cast should be fine, so long as your subclasses are sensible. And I agree that if you can get away with it, it's simpler :)
Jon Skeet
A: 

Here is nice hairy example:

  class Pair<TCar, TCdr>
  {
    public TCar Car { get; set; }
    public TCdr Cdr { get; set; }
  }

  class List<T> : Pair<T, List<T>>, IEnumerable<T>
  {
    public List(T car, List<T> cdr)
    {
      Car = car;
      Cdr = cdr;
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
      yield return Car;
      var cdr = Cdr;
      while (cdr != null)
      {
        yield return cdr.Car;
        cdr = cdr.Cdr;
      }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return ((IEnumerable<T>)this).GetEnumerator();
    }
  }
leppie