Cannot read interface property from a subclass that implements it? - c#

Apologies if this is duplicate, I'm not familiar enough with the correct terminology to know if this is asked elsewhere. I'm new to interfaces and am creating some sample code to see what kind of helpful things they can achieve.
I have a method that returns two possible classes that both implement the same interface. However, I can only access the properties from the parent class and not the sub-class, and have failed to find an explanation. I realise my entire approach may be flawed and will accept that advise also.
This is better explained with an example (NetFiddle) and questions...
using System;
public interface IAb
{
int Prop1 { get; set; }
}
public class A : IAb
{
public int Prop1 { get; set; }
}
public class B : A, IAb
{
public string Prop2 { get; set; }
}
public class Program
{
static class MyMethods
{
public static IAb CreateObject(Type t)
{
if (t == typeof(A))
{
return new A() {Prop1 = 123};
}
else
{
return new B() {Prop1 = 456, Prop2 = "Foo"};
}
}
}
public void Main()
{
IAb AorB = MyMethods.CreateObject(typeof(B));
Console.WriteLine(AorB.Prop1);
if (AorB is B)
{
// fails
// Console.WriteLine((B)AorB.Prop2); // 'IAb' does not contain a definition for 'Prop2'
// works
B newVar = (B)AorB;
Console.WriteLine(newVar.Prop2);
}
}
}
Based on the above:
Why does AorB.Prop1 work, but not AorB.Prop2 without an explicit cast?
Does the above mean that an interface should always be cast to a class before reading it's properties?
Is there a better way to specify the return type of the example method? The current approach feels error-prone because this (albeit unlikely code) would cause an error: var AorB = (B) MyMethods.CreateObject(typeof(A));

You may use pattern matching with is operator to make it more clear
IAb AorB = MyMethods.CreateObject(typeof(B));
Console.WriteLine(AorB.Prop1);
if (AorB is B b)
{
Console.WriteLine(b.Prop2);
}
Your failed line becomes correct after using right parenthesis
Console.WriteLine(((B)AorB).Prop2);
There is also no need to inherit B class from both A class and IAB interface. Since A already implements IAB, you can simply use public class B : A
Is there a better way to specify the return type of the example
method?
Make the CreateObject method generic and use constraints to restrict T type parameter to class, which implements IAb interface and has a parameterless constructor (this's what new() means exactly)
public static T CreateObject<T>() where T : IAb, new()
{
return new T { Prop1 = 123 };
}
and invoke it in the following way
IAb AorB = MyMethods.CreateObject<B>();
But in this case you can set only properties, defined in IAb interface, not the B class specific.

Why does AorB.Prop1 work, but not AorB.Prop2 without an explicit cast?
Because the property selector has precedence over the type cast. Just add parentheses:
Console.WriteLine(((B)AorB).Prop2);
Does the above mean that an interface should always be cast to a class before reading it's properties?
No.
Is there a better way to specify the return type of the example method? The current approach feels error-prone because this (albeit unlikely code) would cause an error: var AorB = (B) MyMethods.CreateObject(typeof(A));
You could use generics:
T CreateObject<T>() where T : new()
{
return new T();
}
However, that does not provide you with compile-time access to properties as in your example. You could slightly improve by providing versions of the method with appropriate constraints:
T CreateObject<T>() where T : IAb, new()
{
var result = new T();
result.Prop1 = 123;
return result;
}

Related

Interface downcasting with generics

I have the following code where I want to downcast to an interface with generic but I get Run-time exception: Unable to cast object of type 'FinalAssociator' to type 'IAssociator`1[Common]'.
public interface ICommon
{
string Name {get;set;}
}
public class Common : ICommon
{
public string Name {get;set;}
}
public class FinalCommon : Common {}
public interface IAssociator<T> where T : ICommon
{
void HandleEvent(T data);
}
public abstract class Associator<T> : IAssociator<T> where T : ICommon
{
public abstract void HandleAnotherEvent(T data);
public void HandleEvent(T data)
{
HandleAnotherEvent(data);
}
}
public class FinalAssociator : Associator<FinalCommon>
{
public override void HandleAnotherEvent(FinalCommon data)
{
Console.WriteLine(data.Name);
}
}
var x = new FinalAssociator();
var y = new FinalCommon { Name = "John" };
var z = (IAssociator<Common>)x;
z.HandleEvent(y);
You can't do this because it could lead to runtime errors due to invalid types, which is one of the things generics is intended to prevent. Consider what would happen if the compiler allowed your code. You have:
z.HandleEvent(y);
Here y is an instance of FinalCommon, which won't present a problem. However, what if you instead passed in something else, like:
z.HandleEvent(new Common());
This would result in your passing an instance of something that isn't FinalCommon to your method that is definitely expecting an instance of FinalCommon. This would be illegal, and the compiler prevents you from getting into this situation.
FinalAssociatior inherits from Associator<FinalCommon>. Its HandleAnotherEvent method expects an argument of type FinalCommon.
If you could cast an instance of it as IAssociator<Common> then you'd be able to pass an argument of type Common to it, even though the class expects FinalCommon.
var finalAssociator = new FinalAssociator();
var commonAssociator = (IAssociator<Common>)finalAssociator; // can't do this
// You'd be able to do this because the interface allows it, but it doesn't
// make sense because the object is a FinalAssociator
// and it doesn't take this argument.
commonAssociator.HandleAnotherEvent(new Common());
As written, the compiler is unable to determine that this is invalid, which is why you get a runtime error. (Resharper provides a warning that this may fail at runtime.)

C# nameof of generics with constraints on type

Given class:
public interface ITest
{
DateTime DataIns { get; set; }
}
And given the class:
public abstract class ATest<T> where T : class, ITest
{
public void Test() {
// I would like to do this:
// var field = nameof(T.DataIns);
}
}
Is it not possible to get the nameof interface property without using the interface itself? I know that, of course, is possible to do that var field = nameof(IMetrics.DataIns); , but I would like to refer to the generics type.
Looks like it is unlikely to happen: https://github.com/dotnet/csharplang/issues/810
You can cheat a bit and go via something that generates a T symbol, since nameof is a compile-time construct. In some sense this is better than coding against the interface as it does the right thing at compilation, however that's more a matter of opinion.
public abstract class ATest<T> where T : class, ITest
{
public void Test()
{
var field = nameof(THack.DataIns);
}
static T THack => throw new NotImplementedException();
}
Considering that this can be done, it is a bit silly that you cannot use T directly.

Can't define static abstract string property

I've run into an interesting problem and am looking for some suggestions on how best to handle this...
I have an abstract class that contains a static method that accepts a static string that I would like to define as an abstract property. Problem is that C# doesn't doesn't support the following (see the ConfigurationSectionName and Current properties):
public abstract class ProviderConfiguration : ConfigurationSection
{
private const string _defaultProviderPropertyName = "defaultProvider";
private const string _providersPropertyName = "providers";
protected static string ConfigurationSectionName { get; }
public static Configuration Current
{
get { return Configuration)ConfigurationManager.GetSection(ConfigurationSectionName); }
}
}
I suppose one way to handle this would be to make ConfigurationSectionName NOT abstract and then create a new definition of ConfigurationSectionName in the derived classes, but that feels pretty hackish. Any suggestions would be most welcome.
Gratias!!!
Static members do not have polymorphism, so they can't be abstract. :(
If that's what you need, consider making a Singleton object, and reading the property off that object.
Just use new to override a static method in a derived class. Nothing that makes new a bad thing to do for virtual methods and properties applies since the type name must be supplied:
public class BaseClass
{
public static int Max { get { return 0; } }
}
public class InteriorClass : BaseClass
{
}
public class DerivedClass : InteriorClass
{
public new static int Max { get { return BaseClass.Max + 1; } }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("BaseClass.Max = {0}", BaseClass.Max);
Console.WriteLine("InteriorClass.Max = {0}", InteriorClass.Max);
Console.WriteLine("DerivedClass.Max = {0}", DerivedClass.Max);
Console.ReadKey();
}
}
Ok, this is not exactly to create an static abstract property, but you can achieve the desired effect.
You can get this by using generics:
public abstract class MyAbstractClass<T>
{
public static string MyAbstractString{ get; set; }
public static string GetMyAbstracString()
{
return "Who are you? " + MyAbstractString;
}
}
public class MyDerivedClass : MyAbstractClass<MyDerivedClass>
{
public static new string MyAbstractString
{
get
{
return MyAbstractClass<MyDerivedClass>.MyAbstractString;
}
set
{
MyAbstractClass<MyDerivedClass>.MyAbstractString = value;
}
}
}
public class MyDerivedClassTwo : MyAbstractClass<MyDerivedClassTwo>
{
public static new string MyAbstractString
{
get
{
return MyAbstractClass<MyDerivedClassTwo>.MyAbstractString;
}
set
{
MyAbstractClass<MyDerivedClassTwo>.MyAbstractString = value;
}
}
}
public class Test
{
public void Test()
{
MyDerivedClass.MyAbstractString = "I am MyDerivedClass";
MyDerivedClassTwo.MyAbstractString = "I am MyDerivedClassTwo";
Debug.Print(MyDerivedClass.GetMyAbstracString());
Debug.Print(MyDerivedClassTwo.GetMyAbstracString());
}
}
So, calling the test class you will get:
"Who are you? I am MyDerivedClass"
"Who are you? I am MyDerivedClassTwo"
So, you have an static method in an abstract class but the abstract value is different for each derived class, nice :D
Ok, so, what's going here? The trick is the generic tag, the compiler is generating a different abstract class for each derived type.
As I said it's not an abstract property, but you get all benefits of abstract static properties, which are programming static functions on your abstract class but using different static parameters per type.
Elsewhere on this page, #Gusman proposes the nice solution distilled here:
abstract class AbstractBase { };
abstract class AbstractBase<T> : AbstractBase
{
public static String AbstractStaticProp { get; set; }
};
class Derived1 : AbstractBase<Derived1>
{
public static new String AbstractStaticProp
{
get => AbstractBase<Derived1>.AbstractStaticProp;
set => AbstractBase<Derived1>.AbstractStaticProp = value;
}
};
class Derived2 : AbstractBase<Derived2>
{
public static new String AbstractStaticProp
{
get => AbstractBase<Derived2>.AbstractStaticProp;
set => AbstractBase<Derived2>.AbstractStaticProp = value;
}
};
Moving the static property from a non-generic to generic class means there is no longer necessarily a single global instance. There will be a unique AbstractStaticProp for each distinct type T, so the idea is that specifying the type of the derived class(es) themselves for T guarantees each of them generates a unique static for themselves. There are a few hazards to note with this, however.
If for some reason it is not acceptable for AbstractBaseClass to be generic, then you've only moved the problem elsewhere (albeit more clearly distilled), because you still have to figure out how to statically call from AbstractBase to AbstractBase<T>.
Mainly, there is nothing to enforce or require that any/every given derived class actually does "implement" the (psudo-) "overridden" static property;
Related to this, since there is no compiler (polymorphic) unification going on here, correct signatures (method name, parameter arity, typing, etc.) for the "overridden" methods aren't enforced either.
Although the generic parameter is intended to be "TSelf" of a derived class, in reality T is unconstrained and essentially arbitrary. This opportunizes two new classes of bug: if base class specification Y : AbstractBase<...> mistakenly references a different AbstractBase‑der­ived class X, the values of the "abstract static property" for X and Y will be incorrectly conflated -- and/or -- any usage call-site AbstractBase<T>.AbstractStaticProp with a mistaken type argument (such as DateTime) will spontaneously--and silently--demand a fresh new "instance" of the static property.
The last bullet point can be somewhat mitigated by adding a constraint on the generic base:
/// v---- constraint added
abstract class AbstractBase<TSelf> where TSelf : AbstractBase<TSelf>
{
public static String AbstractStaticProp { get; set; }
};
This eliminates the possibility of class Derived2 : AbstractBase<DateTime> { /*...*/ }, but not the error class Derived2 : AbstractBase<Derived1> { /*...*/ }. This is due to a recurring conundrum that foils all attempts at constraining a generic type to some exact branch of the type-inheritance hierarchy:
The "TSelf problem"
Generic constraints are always at the mercy of the type arguments that are supplied, which seems to entail that it's impossible to construct a generic constraint that guarantees that some particular TArg within its scope refers to a type that is derived from itself, that is, the immediate type being defined.
The error in this case is an example of this; while the constraint on AbstractBase<TSelf> rules out incompatible disjoint types, it can't rule out the unintended usage Derived2 : AbstractBase​<Derived1>. As far as AbstractBase is concerned, the supplied type argument Derived1 satisfies its constraint just fine, regardless of which of its subtypes is deriving itself (im-)properly. I've tried everything, for years, to solve TSelf; if anyone knows a trick I've missed, please let me know!
Anyway, there are still a couple other points to mention. For example, unless you can immediately spot the problem in the following code, you'll have to agree that it's a bit dangerous:
public static new String AbstractStaticProp
{
get => AbstractBase<Derived1>.AbstractStaticProp;
set => AbstractBase<Derived2>.AbstractStaticProp = value;
}
Ideally, you want to get the compiler to do what it's meant to, namely, understand that all AbstractStaticProp property instances are related and thus somehow enforce their unification. Since that's not possible for static methods, the only remaining option is to eliminate the extra versions, effectively reducing the problem to the unification of just one, a vacuous operation, obviously.
It turns out that the original code is being too elaborate; the generic-base class approach wants to collapse on the simpler solution all by itself without having to explicitly request it, such as those new-marked properties seem to be doing with the qualification in AbstractBase<Derived1>.​AbstractStaticProp".
You can already refer to each respective independent copy of the static property by qualifying with the derived class name instead (in fact, #Gusman's test harness shows this), so the end result is that the property declarations in the derived class aren't necessary at all. Without further ado, here is the complete simplified version:
abstract class AbstractBase { };
abstract class AbstractBase<TSelf> : AbstractBase
where TSelf : AbstractBase<TSelf>
{
public static String AbstractStaticProp { get; set; }
};
class Derived1 : AbstractBase<Derived1> { };
class Derived2 : AbstractBase<Derived2> { };
This works identically to the code at the top. The test harness gives the same results as before.
static void Test()
{
Derived1.AbstractStaticProp = "I am Derived1";
Derived2.AbstractStaticProp = "I am Derived2";
Debug.Print(Derived1.AbstractStaticProp); // --> I am Derived1
Debug.Print(Derived2.AbstractStaticProp); // --> I am Derived2
}
What you're trying to do is impossible, as others have mentioned.
I'd try something like this
public abstract class ProviderConfiguration : ConfigurationSection
{
public string ConfigurationSectionName { get; set; }
public static ProviderConfiguration Provider { get; set; }
public static Configuration Current
{
get { return (Configuration)ConfigurationManager.GetSection(Provider.ConfigurationSectionName); }
}
}
Then in practice:
public void DoStuff()
{
var provider = new DerivedProviderConfiguration();
ProviderConfiguration.Provider = provider;
}

Can I force a subclass to declare a constant?

I want to force subclasses to define a constant value.
Like
const string SomeConstantEverySubclassMustDefine = "abc";
I need that because I need to have it tied to the Type, rather than to the instance and you can't override static Methods/Properties iirc.
I'd really like to have a compile-time check for those constants.
Let me explain in more detail:
Some classes in our Domain-Model are special, you can take certain actions for them, depending on the type. Thus the logic is tied to the type. The action to be taken requires a string tied to the type. I sure could create an instance everytime as a workaround and declare an abstract property, but that's not what I want. I want to enforce the declaration of the string at compile-time, just to be sure.
No, you can't. I would suggest you make your base class abstract, with an abstract property which you can fetch when you want. Each child class can then implement the property just by returning a constant if it wants. The downside is that you can't use this within static methods in the base class - but those aren't associated with the child classes anyway.
(It also allows child classes to customise the property per instance as well, if necessary... but that's rarely an actual problem.)
If this doesn't do enough for you, you might want to consider a parallel type hierarchy. Basically polymorphism simply doesn't happen in a type-specific way in .NET; only in an instance-specific way.
If you still want to do this and fetch it with reflection, I suggest you just write unit tests to ensure that the relevant constants are defined. When you get beyond what the type system can describe, that's often the best you can do.
Make an abstract property with only a get. That's what I think you could do to enforce a class has a value. Then you can just return a constant in the property.
Example:
Base class:
public abstract string MyConst { get; }
Derived class:
public override string MyConst {
get { return "constant"; }
}
Here is how I made mine work. I used Attribute as others have suggested.
public class ObjectAttribute : Attribute
{
public int ObjectSize { get; set; }
public ObjectAttribute(int objectSize)
{
this.ObjectSize = objectSize;
}
}
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
[ObjectAttribute(15)]
public class AObject : BaseObject
{
public string Code { get; set; }
public int Height { get; set; }
}
[ObjectAttribute(25)]
public class BObject : BaseObject
{
public string Code { get; set; }
public int Weight { get; set; }
}
If you would like instance access to the attribute just add it to the base abstract class.
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
public int ObjectSize
{
get
{
ObjectAttribute[] attributes = (ObjectAttribute[])GetType().GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
}
Usage of the constants
int constantValueA = AObject.GetObjectSize<AObject>();
int constantValueB = BObject.GetObjectSize<BObject>();
AObject aInstance = new AObject();
int instanceValueA = aInstance.ObjectSize;
New idea
Here's a sort of weird idea: instead of using inheritance directly, you create a separate class to provide a constant value for every type deriving from some type T. The constructor for this type uses reflection to verify that every derived type has indeed been supplied a value.
public abstract class Constant<T, TConstant>
{
private Dictionary<Type, TConstant> _constants;
protected Constant()
{
_constants = new Dictionary<Type, TConstant>();
// Here any class deriving from Constant<T, TConstant>
// should put a value in the dictionary for every type
// deriving from T, using the DefineConstant method below.
DefineConstants();
EnsureConstantsDefinedForAllTypes();
}
protected abstract void DefineConstants();
protected void DefineConstant<U>(TConstant constant) where U : T
{
_constants[typeof(U)] = constant;
}
private void EnsureConstantsDefinedForAllTypes()
{
Type baseType = typeof(T);
// Here we discover all types deriving from T
// and verify that each has a key present in the
// dictionary.
var appDomain = AppDomain.CurrentDomain;
var assemblies = appDomain.GetAssemblies();
var types = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => baseType.IsAssignableFrom(t));
foreach (Type t in types)
{
if (!_constants.ContainsKey(t))
{
throw new Exception(
string.Format("No constant defined for type '{0}'.", t)
);
}
}
}
public TConstant GetValue<U>() where U : T
{
return _constants[typeof(U)];
}
}
Basic example:
public class BaseType
{
public static Constant<BaseType, string> Description { get; private set; }
static BaseType()
{
Description = new BaseTypeDescription();
}
}
public class DerivedType : BaseType
{ }
internal sealed class BaseTypeDescription : Constant<BaseType, string>
{
public BaseTypeDescription() : base()
{ }
protected override DefineConstants()
{
DefineConstant<BaseType>("A base type");
DefineConstant<DerivedType>("A derived type");
}
}
Now I have code that allows me to do this:
var description = BaseType.Description;
// returns "A base type"
string baseTypeDescription = description.GetValue<BaseType>();
// returns "A derived type"
string derivedTypeDescription = description.GetValue<DerivedType>();
Original answer
You may not like it, but the closest way to accomplish this is by declaring an abstract read-only (no set) property.
If you've got an instance of your subclass, then this can work just as well as a constant, even though it is technically instance-level (it will just be the same for all instances of the given class).
Consider, for instance, IList.IsReadOnly. In most cases this is actually a property that tells you about the underlying class implementation, as opposed to any state specific to a particular instance. (It may be an interface member as opposed to an abstract class member, but it's the same idea.)
If you are trying to access it statically, well... then you're out of luck. But in this case I fail to see how you'd obtain the value without using reflection anyway. Maybe that's your intention; I don't know.
You could have a static method in the base class called, for instance "Register", that is passed a Type and a constant value, with the intention being that it is called by the class constructors of the subtypes. Then, add a check in all of your base class constructors that the object being constructed is of a registered type.
abstract class Base
{
private static Dictionary<Type, string> _registry = new Dictionary<Type, string>();
protected static void Register(Type t, string constVal)
{
_registry.Add(t, constVal);
}
protected Base()
{
if(!_registry.ContainsKey(this.GetType()))
throw new NotSupportedException("Type must have a registered constant");
}
public string TypeConstant
{
get
{
return _registry[this.GetType()];
}
}
}
class GoodSubtype : Base
{
static GoodSubtype()
{
Base.Register(typeof(GoodSubtype), "Good");
}
public GoodSubtype()
: base()
{
}
}
class Badsubtype : Base
{
public Badsubtype()
: base()
{
}
}
And then elsewhere, you can construct GoodSubtype instances, but trying to construct a Badsubtype gets an exception. I think a runtime error at construction is the soonest you can get an error with this type of scheme.
(You'd want to use ConcurrentDictionary for your registry if threading is involved)
There's one other method that hasn't been covered and it uses the new modifier to hide consts values in the base class. In a way, it's similar to Nap's solution, but doesn't allow per-instance access and therefore doesn't allow for polymorphic access within the base class. This solution is only useful if you want to have constant value defined but wish to have the option of changing it to different values in different subclasses.
static void Main(string[] args)
{
Console.WriteLine("BaseClass.MyConst = {0}, ClassA.MyConst = {1}, ClassB.MyConst = {2}", BaseClass.MyConst, ClassA.MyConst, ClassB.MyConst);
Console.ReadKey();
}
class BaseClass
{
public const int MyConst = 1;
}
class ClassA : BaseClass
{
public new const int MyConst = 2;
}
class ClassB : BaseClass
{
}

Upcasting in .NET using generics

So I've got a class like this:
public class A {
internal A(int i) { ... }
public int Foo { get; set; }
}
This class is then inherited by a bunch of generated classes, eg:
public class B : A {
...
}
The int based constructor isn't exposed to the inherited class (for design reasons I don't want it exposed). In my library which holds the definition for class A I've got a method like this:
public T Load<T>() where T : A {
//do some stuff, create an instance of T from an int, then return it
}
And then I'd use it like this:
B b = Helper.Load<B>();
Since the constructor I want to use isn't exposed to class B when I do typeof(T).GetConstructor(typeof(int)) I don't get the constructor back, so I want thinking that I'd do this:
return (T)new A(/*some int */);
But that gives me a runtime error System.InvalidCastException, that I can't cast a type A to type B.
How do I go about achieving this upcasting?
You can just use default constructors so you can instantiate objects of type T with the new() constraint. Then class A can have a virtual (or abstract to your liking) method that takes an int as an argument and initializes the object after the constructor has run.
public class A {
internal A() { }
internal Initialize(int i) { Foo = i; }
public int Foo { get; set; }
}
public class B : A {
internal B() { }
}
...
public T Load<T>() where T : A, new() {
var ret = new T();
ret.Initialize(i);
return ret;
}
If you intend some sort of factory pattern, you don't need to hesitate initializing parts of an object outside the constructor call as long as it is done before you return the object to the caller's control.
From what I understood, T derives from A, so you can't cast A to T.
You can't upcast A to B in your example, because:
return (T)new A(/*some int */);
Instantiates an A, which is not a B. Just because a "B is an A" does not mean "A is a B". You would have to first instantiate a B, cast it to an A, do what you want, and then upcast it back to a B.
I'm not sure if this is will compile, but you could try this:
T blah = new T(5); //this means your B will need to implement a int constructor
A blah2 = (A)blah;
//operate on A specific operations in blah2
T upcasted = (T)blah2;
//alternatively
T upcasted = blah2 as T;
Consider refactoring your contructor such that you initialize the integer as a property, instead of a parameter of the constructor. I strive to have default(no parameters) contructors so that generic code can instantiate the class easily.
You cant do this, change your design.

Categories