使用Base属性而不是声明

时间:2017-03-22 12:18:33

标签: c# inheritance

我很难理解为什么它会返回基值而不是实际值。我需要确定有Prop,但我想使用实际值而不是基值。

public interface IA
{
    string Value { get; set; }
}

public class A : IA
{
    public String Value { get; set; }
}

public class B
{
    public IA Prop { get; set; }
}

public class C : B
{
    public new A Prop { get; set; }

    public C()
    {
        Prop = new A();
        Prop.Value = "test C";
    }
}


public static class D
{
    public static string GetDynamicProp(dynamic item)
    {
        return item.Prop.Value;
    }

    public static string GetProp<T>(T item) where T : B
    {
        return item.Prop.Value;
    }

}

然后使用它:

var test = new C();
Console.WriteLine(test.Prop.Value);        // test C
Console.WriteLine(C.GetDynamicProp(test)); // test C
Console.WriteLine(D.GetProp(test));        // null reference exception because it is using the `IA Prop` from `B`

当使用动态类型时它确实有效,但是我不能使用intellisense作为例子。所以我想确保发送到D.GetProp的对象实现IA的属性,但仍使用实际值。

我希望Prop始终属于实现IA的类型,但它可以是继承类型。

2 个答案:

答案 0 :(得分:3)

您在B.Prop中使用new隐藏了class C,而不是覆盖它。

我希望这是因为你无法覆盖它,因为它与基类中的属性具有相同的名称,但具有不同的类型。你不允许那样做。

解决此问题的一种方法是将属性的类型更改为与基类中的类型相同,并将其设置为虚拟。然后你可以override,就像这样:

public interface IA
{
    string Value { get; set; }
}

public class A : IA
{
    public String Value { get; set; }
}

public class B
{
    public virtual IA Prop { get; set; }
}

public class C : B
{
    public override IA Prop { get; set; }

    public C()
    {
        Prop = new A();
        Prop.Value = "test C";
    }
}

然后代码将打印&#34;测试c&#34;正如你所料。

有一个很好的理由是你不允许覆盖不同类型的属性 - 因为你可以通过基类设置属性,因此你可能违反了类型系统,如果你被允许这样做。

一个例子可以说清楚。假设您有以下内容:

public interface IMammal
{
}

public class Dog : IMammal
{
    public void Bark()
    {
        Console.WriteLine("Woof");
    }
}

public class Cat : IMammal
{
    public void Meow()
    {
        Console.WriteLine("meow");
    }
}

public class Pet
{
    public virtual IMammal Animal { get; set; }
}

现在进一步假设您可以覆盖Pet.Animal来自IMammal的类型:

public class DoggyPet : Pet
{
    public override Dog Animal { get; set; } // NOT ALLOWED!
}

如果允许,那么这样的代码将编译:

DoggyPet doggy = new DoggyPet();
doggy.Animal = new Dog(); // OK so far.
doggy.Bark(); // No problems.

Pet pet = doggy; // Assign to base class.
pet.Animal = new Cat(); // Yikes! just changed doggy.Animal to a cat!
doggy.Bark(); // What happens now! Ooops.

注意:当然,如果您没有物业的设定者,那么这个问题就不会出现,所以理论上这应该是可能的。此功能称为&#34;返回类型协方差&#34; - 但C#不支持。

See this thread for more information about "return type covariance" and a potential workaround.

答案 1 :(得分:2)

根据你的评论你知道编译时的实际类型,所以为了能够使用IntelliSense(即具有实际类型的编译时知识)并且仍然能够为所有派生使用通用接口您可以使用接口和基类的组合以及类似的通用Cast<T>方法:

using System;
using System.Text.RegularExpressions;

public interface IA
{
    string Value { get; set; }

    T Cast<T>() where T : class, IA;
}

public abstract class ABase : IA
{
    public virtual string Value { get; set; }

    public T Cast<T>() where T : class, IA
    {
        return this as T;
    }
}

public class A : ABase
{
    // redundant, not really needed
    public override String Value { get; set; }
}

public class A2 : ABase
{
    // redundant, not really needed
    public override String Value { get; set; }

    public String Value2 { get; set; }
}

public class B
{
    public IA Prop { get; set; }
}

public class C : B
{
    public C()
    {
        Prop = new A();
        Prop.Value = "test C";
    }
}

public class C2 : B
{
    public C2()
    {
        Prop = new A2();
        Prop.Value = "test C2";
        Prop.Cast<A2>().Value2 = "test C2 Value2";
    }
}

public static class D
{
    public static string GetDynamicProp(dynamic item)
    {
        Console.WriteLine(item.GetType().FullName);
        Console.WriteLine(item.Prop.GetType().FullName);
        return item.Prop.Value;
    }

    public static string GetProp<T>(T item) where T : B
    {
        Console.WriteLine(item.GetType().FullName);
        Console.WriteLine(item.Prop.GetType().FullName);
        return item.Prop.Value;
    }

}

public class Program
{

    public static void Main()
    {
        var test = new C();

        Console.WriteLine(test.Prop.Value);        // test C

        Console.WriteLine(D.GetDynamicProp(test)); // test C

        Console.WriteLine(D.GetProp(test)); 

        var test2 = new C2();

        Console.WriteLine(test2.Prop.Value);        // test C2

        Console.WriteLine(D.GetDynamicProp(test2)); // test C2

        Console.WriteLine(D.GetProp(test2));        // test C2

        Console.WriteLine(D.GetProp(test2));        // test C2

        Console.WriteLine(test2.Prop.Cast<A2>().Value);         // test C2
        Console.WriteLine(test2.Prop.Cast<A2>().Value2);        // test C2 Value2

    }
}

输出将如下所示:

test C
C
A
test C
C
A
test C
test C2
C2
A2
test C2
C2
A2
test C2
C2
A2
test C2
test C2
test C2 Value2

虽然Cast<T>()方法调用比直接投射(SomeType) baseType长约4倍,但我们发现它在我们的项目中可以忽略不计(BenchmarkDotNet在我的开发机器上给我的速度为61ns vs 15ns)。 / p>