Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Base属性而不是声明的_C#_Inheritance - Fatal编程技术网

C# 使用Base属性而不是声明的

C# 使用Base属性而不是声明的,c#,inheritance,C#,Inheritance,我很难理解为什么它返回的是基值而不是实际值。我需要确保有一个属性,但我想使用实际值,而不是基本值 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 { publ

我很难理解为什么它返回的是基值而不是实际值。我需要确保有一个
属性
,但我想使用实际值,而不是基本值

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;
    }

}
当使用动态类型时,它确实起作用,但我不能使用intellisense作为例子。因此,我希望确保发送到
D.GetProp
的对象实现了
IA
的属性,但仍然使用实际值


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

您在
类C
中使用
新的
来隐藏
B.Prop
,而不是覆盖它

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

解决此问题的一种方法是将属性的类型更改为与基类中的类型相同,并使其成为虚拟的。然后您可以覆盖它,如下所示:

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";
    }
}
然后,代码将按预期打印“testc”

有一个很好的理由不允许您使用不同的类型重写属性-这是因为您可以通过基类设置属性,因此如果允许您这样做,您可能会违反类型系统

举例说明。假设您有以下内容:

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.
注意:当然,如果您没有属性的setter,则不会出现此问题,因此理论上这应该是可能的。这一特性被称为“返回型协方差”——但C#不支持这一点


类别C
中使用
new
隐藏
B.Prop
,而不是覆盖它

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

解决此问题的一种方法是将属性的类型更改为与基类中的类型相同,并使其成为虚拟的。然后您可以覆盖它,如下所示:

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";
    }
}
然后,代码将按预期打印“testc”

有一个很好的理由不允许您使用不同的类型重写属性-这是因为您可以通过基类设置属性,因此如果允许您这样做,您可能会违反类型系统

举例说明。假设您有以下内容:

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.
注意:当然,如果您没有属性的setter,则不会出现此问题,因此理论上这应该是可能的。这一特性被称为“返回型协方差”——但C#不支持这一点


根据您的评论,您知道编译时的实际类型,因此为了能够使用IntelliSense(即拥有实际类型的编译时知识)并且仍然能够为所有派生类使用公共接口。您可以使用接口和基类的组合,使用泛型
Cast
方法,如下所示:

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(),因此,为了能够使用IntelliSense(即拥有实际类型的编译时知识),并且仍然能够为所有派生类使用公共接口,您可以使用接口和基类的组合,并使用泛型
Cast
方法,如下所示:

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

<> > <代码> Case>(/Cuth>方法调用)比直接CAST <代码>(Sytype)BaseType 是的,但是考虑到<代码> A < /C>还有几个其他属性。在C类中将其声明为
IA
,这意味着我只能使用intellisense的值,而不能使用其他属性。@HugoDelsing是的,这是真的-但继承在C#中就是这样工作的。没有简单的解决办法。是的,但是考虑到<代码> 还有几个其他属性。在C类中将其声明为
IA
,这意味着我只能使用intellisense的值,而不能使用其他属性。@HugoDelsing是的,这是真的-但继承在C#中就是这样工作的。没有简单的解决方法。>我希望道具始终是实现IA的类型,但它可以是继承的类型。在编译时,您是否已经知道您在
Prop
中实际继承了哪种类型的
IA
?或者你只知道在运行时吗?@RonaldRink'd-fens'我在类
C
中声明了实际的类型。这就是我知道它是什么的时候。>我希望道具始终是实现IA的类型,但它可以是继承的类型。在编译时,您是否已经知道您在
Prop
中实际继承了哪种类型的
IA
?或者你只知道在运行时吗?@RonaldRink'd-fens'我在类
C
中声明了实际的类型。那时我才知道它是什么。