문제

내가 아는 한 C# 2.0에서 다음을 수행하는 것은 불가능합니다.

public class Father
{
    public virtual Father SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

public class Child : Father
{
    public override Child SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

파생 클래스의 속성을 "신규"로 만들어서 문제를 해결하지만 물론 다형성은 아닙니다.

public new Child SomePropertyName

2.0에 솔루션이 있습니까? 이 문제를 해결하는 3.5의 기능은 어떻습니까?

도움이 되었습니까?

해결책

This is not possible in any .NET language because of type-safety concerns. In type-safe languages, you must provide covariance for return values, and contravariance for parameters. Take this code:

class B {
    S Get();
    Set(S);
}
class D : B {
    T Get();
    Set(T);
}

For the Get methods, covariance means that T must either be S or a type derived from S. Otherwise, if you had a reference to an object of type D stored in a variable typed B, when you called B.Get() you wouldn't get an object representable as an S back -- breaking the type system.

For the Set methods, contravariance means that T must either be S or a type that S derives from. Otherwise, if you had a reference to an object of type D stored in a variable typed B, when you called B.Set(X), where X was of type S but not of type T, D::Set(T) would get an object of a type it did not expect.

In C#, there was a conscious decision to disallow changing the type when overloading properties, even when they have only one of the getter/setter pair, because it would otherwise have very inconsistent behavior ("You mean, I can change the type on the one with a getter, but not one with both a getter and setter? Why not?!?" -- Anonymous Alternate Universe Newbie).

다른 팁

You can re-declare (new), but you can't re-declare and override at the same time (with the same name). One option is to use a protected method to hide the detail - this allows both polymorphism and hiding at the same time:

public class Father
{
    public Father SomePropertyName
    {
        get {
            return SomePropertyImpl();
        }
    }
    protected virtual Father SomePropertyImpl()
    {
        // base-class version
    }
}

public class Child : Father
{
    public new Child SomePropertyName
    {
        get
        { // since we know our local SomePropertyImpl actually returns a Child
            return (Child)SomePropertyImpl();
        }
    }
    protected override Father SomePropertyImpl()
    {
        // do something different, might return a Child
        // but typed as Father for the return
    }
}

No, but you can use generics in 2 and above:

public class MyClass<T> where T: Person
{
    public virtual T SomePropertyName
    {
        get
        {
            return  ...;
        }
    }
}

Then Father and Child are generic versions of the same class

From Wikipedia:

In the C# programming language, support for both return-type covariance and parameter contravariance for delegates was added in version 2.0 of the language. Neither covariance nor contravariance are supported for method overriding.

It doesn't explicitly say anything about covariance of properties though.

You can create a common interface for father and child and return a type of that interface.

No. C# does not support this idea (it's called "return type covariance"). You can however do this:

public class FatherProp
{
}

public class ChildProp: FatherProp
{
}


public class Father
{
    public virtual FatherProp SomePropertyName
    {
        get
        {
            return new FatherProp();
        }
    }
}


public class Child : Father
{
    public override FatherProp SomePropertyName
    {
        get
        {
            // override to return a derived type instead
            return new ChildProp();
        }
    }
}

i.e. use the contract defined by the base class, but return a derived type. I have made a more detailed sample to make this point clearer - returning "this" again wouldn't change anything.

It is possible (but messy) to test the returned object for it's actual type (i.e. "if someObject is ChildProp"), but it is better to call a virtual method on it that does the right thing for its type.

The base class virtual method (in this case, virtual property) not only has an implementation, but also defines a contract: that a child class can supply a different implementation of SomePropertyName if it meets this contract (i.e. SomePropertyName returns an object of type "FatherProp"). Returning an object of type "ChildProp" derived from "FatherProp" meets this contract. But you can't change the contract in "Child" - this contract applies to all classes descended from "Father".

If you take a step back and look at your broader design, there are other language constructs in the C# toolkit that you may also want to think about instead - Generics, or interfaces.

No. C# does not support this idea (it's called "return type covariance").

From Wikipedia:

In the C# programming language, support for both return-type covariance and parameter contravariance for delegates was added in version 2.0 of the language. Neither covariance nor contravariance are supported for method overriding.

You can re-declare (new), but you can't re-declare and override at the same time (with the same name). One option is to use a protected method to hide the detail - this allows both polymorphism and hiding at the same time:

The best solutions would be to use generics:

public class MyClass<T> where T: Person
{
   public virtual T SomePropertyNameA
   {        
      get { return  ...; }    
   }
}//Then the Father and Child are generic versions of the same class

This is the closest I could come (so far):

    public sealed class JustFather : Father<JustFather> {}

    public class Father<T> where T : Father<T>
    { public virtual T SomePropertyName
        { get { return (T) this; }
        }
    }

    public class Child : Father<Child>
    { public override Child SomePropertyName
        { get { return  this; }
        }
    }

Without the JustFather class, you couldn't instantiate a Father<T> unless it was some other derived type.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top