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
中声明了实际的类型。那时我才知道它是什么。