Inheriting C # fields

This is probably a stupid question, but here it goes. Perhaps you have the following classes:

public class C { } public class D : C { //A subclass of C } public class A { C argument; } 

Now I want to have a class B that inherits from A. This class obviously inherits the โ€œargumentโ€ field, but I want to force the โ€œargumentโ€ field in B to be of type D, not C. Since D inherits from C, this should not create no problem. So how to achieve this in C #?

+4
source share
8 answers

As Jared points out, this is not possible. However, it is interesting to consider why not.

Assume the field is private. Then it may not be available in the derived class B. (Assuming B is not a nested type of A.)

Assume the field is not private. It does not matter if it is publicly available, internal, protected or protected internal. Suppose his audience and that were legal. Now you have the following situation.

 class B : A { override public D argument; // "overrides" A.argument } class E : C { } class F { public static void M(A a) { a.argument = new E(); } } ... FM(new B()); 

And hey, you just crashed while you work. You just wrote an object of type E in a field that can only store type D. (We could do similar failure scenarios for other configurations, such as protected fields, etc.)

Now you can say, well, instead, let me make the property read-only. What I can virtualize:

 class A { public virtual C Argument { get; } } class B : A { public override D Argument { ... } } 

Now the problems are gone. The open interface is not writable, so there is no problem that someone writes something there that is not supported. And the property is virtual, so there is a mechanism for overriding it.

This function is called "return type covariance," and it is not supported in C #. See Why are the concepts of "Covariance" and "Contravariance" applicable to the implementation of interface methods? .

Please explain what you are really trying to do, not how you are trying to do it. There is probably a better way.

+10
source

You can achieve something like this, where A is a generic type with its type parameter limited to subclasses of C: -

 public class C { } public class D : C { } public class A<T> where T:C { public T Argument { get; set; } } public class B : A<D> { } 

Remember that you should not publish public (or protected) fields, so I changed them to properties.

+3
source

This is not supported in C #. You cannot change the type of an existing field, or property or method, if that matters, by getting a specific type.

+2
source

To make this typical, you have to do something with generics. Otherwise, just throw.

But in general, the presence of non-file fields is not a good solution, because it violates information that hides the principle. Therefore, you should avoid this, if possible, and use properties and / or methods instead.

+1
source

If I didnโ€™t completely miss the boat, I think you are asking for something like this

 class A { public virtual C Argument { get; set; } } class B : A { D argument = null; public override C Argument { get { return argument; } set { if (value is D) { argument = (D)value; } else { throw new Exception(); } } } } class C { } class D : C { } 

...

 static void Main() { B b = new B(); D arg = new D(); b.Argument = arg; } 
+1
source

This is a bit of a simple question. Generally, it is bad practice to hide an argument of a base class with the same name in a derived class.

public class B: A {D argument; }

you can also do this ...

public class B: A {public B () {argument = new D (); }}

0
source

The argument property / method in B can return D, since D inherits from C, but, as JaredPar wrote, it must be entered as C.

0
source

What you are looking for is a language function called return type covariance that C # does not support.

You have one more option: you can "shadow" a field instead of its inheritance. However, this is very dangerous and almost everywhere - a bad idea, because everything that is assigned to an object as B.argument will not be available if it has grown and will be called A.argument.

If you are in C # 4.0, you can get some aspects of what you are trying using a common covariant interface:

 public class C { public int foo; } public class D : C { } public class A : ITest<C> { public C foo { get; private set; } } public class B : ITest<D> { public D foo { get; private set; } } public interface ITest<out T> where T : C { T foo { get; } } static class Program { public static void Covariance(ITest<C> test) { } static void Main() { A myCVar = new A(); B myDVar = new B(); Covariance(myDVar); } } 

Note that the Covariance function will accept B (it is ITest<D> , not ITest<C> ), because the ITest interface marks the parameter T keyword out . This tells the compiler that this type parameter will only be used in output operations. therefore, using this interface it is safe to replace any derived class T

0
source

Source: https://habr.com/ru/post/1305584/


All Articles