Get value of static member of class of current instance in inherited method

Hi there folks,

Yes, the title confuses me too.

It's hard to write in a sentence what I want to do, so I'll show you some code.

abstract class Parent
{
public static string Test { get { throw new InvalidOperation(); } }
public void DoSomething()
{
Console.WriteLine(Test);
}
}

class ChildOne : Parent
{
public new static string Test { get { return "ChildOne"; } }
}

class ChildTwo : Parent
{
public new static string Test { get { return "ChildTwo"; } }
}

With the above code, if you were to create a new instance of ChildOne called test and call test.DoSomething(); you'll get "Parent". This makes perfect sense, I know, because not specifying which class the static member belongs to should default to the one the method is in.

What I want to know is if there's some kind of syntax for substituting the class name of the current instance. Kind of like me.Test or self.Test in some other languages.

I'm not completely helpless here so I already made two solutions to the problem. One involved reflection in which case I could get it to work just as I wanted, but the code for it looked rather horrible ((string)this.GetType().GetProperty("Test").GetValue(null, null)). The other involves making an abstract GetTest() method that returns a string in the Parent class, then overriding it in all Child classes, each one returning Test.

As for the reason I want to do this, it's because I'm storing string information which won't change during runtime (I could use constants, I know) but which should be attached to each individual class deriving from the base class. I'm using the derived classes in generic methods so I won't know what their names are, and I need to call both a DoSomething()-equivalent and access the property statically.
[1952 byte] By [andreasblixt] at [2007-11-20 9:06:07]
# 1 Re: Get value of static member of class of current instance in inherited method
hhmmm, I think I know what you mean. I would recommend the use of interfaces to achieve this. I've written a simple example below:


interface IChildObject
{
string Test { get;}
void DoSomething();
}


class ChildOne : IChildObject
{

public string Test { get { return "ChildOne"; } }

public void DoSomething()
{
throw new NotImplementedException();
}

}

class ChildTwo : IChildObject
{

public string Test { get { return "ChildTwo"; } }

public void DoSomething()
{
throw new NotImplementedException();
}

}


Then you check get the "Test" property for each IChildObject object as shown below:


void TestMyObject(IChildObject child)
{
Console.WriteLine(child.Test);
}


Unless I've read your post completly wrong. In which case. oops :)
Consola at 2007-11-9 11:33:54 >
# 2 Re: Get value of static member of class of current instance in inherited method
Sorry, I'm not entirely sure what you are trying to achieve. But based on the question I've quoted do you mean something like this:


this.DoSomething();

and/or


base.DoSomething();

I want a way to get the value of a static property that's declared in the class of the current instance, not the class of the current method.

Here's one solution I did that shows what results I want:

using System;

namespace Test
{
abstract class BaseClass
{
public static string Test { get { throw new InvalidOperationException(); } }
public abstract string GetTest();
}

class SubClass1 : BaseClass
{
public new static string Test { get { return "SubClass1"; } }
public override string GetTest() { return Test; }
}

class SubClass2 : BaseClass
{
public new static string Test { get { return "SubClass2"; } }
public override string GetTest() { return Test; }
}

class Program
{
static void Main(string[] args)
{
BaseClass test1 = new SubClass1();
Console.WriteLine("test1.GetTest() = '{0}'", test1.GetTest());
Console.WriteLine("SubClass1.Test = '{0}'", SubClass1.Test);

BaseClass test2 = new SubClass2();
Console.WriteLine("test2.GetTest() = '{0}'", test2.GetTest());
Console.WriteLine("SubClass2.Test = '{0}'", SubClass2.Test);

Console.ReadKey(true);
}
}
}

I was just hoping there was a way for me to replace test2.GetTest() with some kind of syntax similar to class(test2).Test. This would save me from having to write one method for each static property in each derived class.

However, I'm realizing more and more why it's not possible because even though a class derives from a base class with a particular static member, the derived class does not necessarily need to have it. The solution would be to use the closest version of the static member in the inheritance hierarchy, but that would change the way the language functions and would need runtime checks.

So I'm coming to the conclusion that I will probably have to use reflection even if it's ugly, but I can hide it in a wrapper method which I only need to define once in the base class, so it's probably not so bad after all.

I ran into another problem as well with accessing a static property of a constrained type parameter, which doesn't work for the same reasons I just mentioned. So there are like big, flashing, red arrows pointing towards System.Reflection.
andreasblixt at 2007-11-9 11:34:55 >
# 3 Re: Get value of static member of class of current instance in inherited method
In response to your edit, Consola:

I need the properties to be static because I don't necessarily have access to an instance of the class. Besides, I don't want memory allocated per instance of a class, only per class.

Many thanks for your invested time, though!
andreasblixt at 2007-11-9 11:35:54 >
# 4 Re: Get value of static member of class of current instance in inherited method
Actually, the more I think about it the more I dislike the idea of making the properties static, because without definite inheritance they aren't guaranteed to be there by the compiler. I can't think of a single way to force a derived class to statically implement something, so I'll probably fall back to putting the values at the instance level.

The problem that arises is that I cannot access the property without a value (well, I probably can with reflection, but I'm trying to avoid that). I'll try to figure out some kind of solution, but I was hoping someone with experience from trying to do the same thing could enlighten me.

Thanks,
Andreas
andreasblixt at 2007-11-9 11:36:49 >
# 5 Re: Get value of static member of class of current instance in inherited method
abstract class Parent
{
public static string Test { get { throw new InvalidOperation(); } }
public void DoSomething()
{
Console.WriteLine(Test);
}
}

class ChildOne : Parent
{
public new static string Test { get { return "ChildOne"; } }
}

class ChildTwo : Parent
{
public new static string Test { get { return "ChildTwo"; } }
}

This is actually a terrible way of doing this. For example:

Parent m = new ChildOne();
Console.WriteLine(m.Test); // this wil throw an exception

Child1 m = new ChildOne();
Console.WriteLine(m.Test); // This will print Child1

If you want the first way to work, then you'd have to define your "Test" method as being 'abstract' or 'virtual' and then overriding it in your derived classes:

abstract class Parent
{
public static abstract string Test { get { throw new InvalidOperation(); } }
public void DoSomething()
{
Console.WriteLine(Test);
}
}

class ChildOne : Parent
{
public static override string Test { get { return "ChildOne"; } }
}

class ChildTwo : Parent
{
public static override string Test { get { return "ChildTwo"; } }
}

The only thing i'll add is that i don't believe you an override static members like that. Also, what's the point in that? What exactly is it you're trying to accomplish? I don't understand what your code is trying to do.
Mutant_Fruit at 2007-11-9 11:37:59 >
# 6 Re: Get value of static member of class of current instance in inherited method
Mutant_Fruit:

Yes, that was some sample code I made to demonstrate my problem (which you also noted). I actually removed the code that made it work so that it wouldn't be in the way. If you look at my second piece of code you'll see the actual way I did it which works.

I've gone back to using instance properties so that inheritance works properly, but now have to create a blank instance of the class to get the properties which will then be discarded by the GC. Somewhat ugly, but I prefer it over using reflection.

Edit:
To elaborate on what I'm trying to achieve, I've got an abstract base class utilizing generics which represents any row in a database. This class automatically generates SQL queries based on the properties in the derived classes, which each represent a table. So they hold key name, column names and table name. When I want to get a single row, putting the properties at the instance level is no problem because I will always be dealing with an instance. But once I want to make a list, I will first be dealing with no instance at all (when building the SQL query that selects the rows I haven't created any instances yet). My solution to getting the properties was to create a blank instance which is never put into use.
andreasblixt at 2007-11-9 11:38:58 >
# 7 Re: Get value of static member of class of current instance in inherited method
This may be a bit off-bat but you could use an attribute to do this :

public class NameAttribute : Attribute
{
private string _name;

public NameAttribute(string name)
{
_name = name;
}

public string Name
{
get
{
return _name;
}
}
}

public class Base
{
private string _name;

public string Name
{
get
{
if (_name == null)
{
NameAttribute[] nameAttributes =
this.GetType().GetCustomAttributes(typeof(NameAttribute), false) as NameAttribute[];

_name = nameAttributes[0].Name;
}

return _name;
}
}
}

[Name("Name1")]
public class Child1 : Base
{

}

[Name("Name2")]
public class Child2 : Base
{

}

class Program
{
static void Main(string[] args)
{
Base child1 = new Child1();
Base child2 = new Child2();
string name1 = child1.Name;
string name2 = child2.Name;
Console.WriteLine("{0} {1}", name1, name2);
}
}

This way you don't have to override any member functions in the base to get at derived classes static data.

Darwen.
darwen at 2007-11-9 11:39:52 >
# 8 Re: Get value of static member of class of current instance in inherited method
andreasblixt:

Your second code example doesn't make any sense either. Using "new" rather than overriding should only really be done when you *can't* override. The reason being that a "new" method will only be called if your class is cast to that exact type.

For example:
BaseClass c = new ChildClass1();
c.CallMethod();

will call a completely different method than
ChildClass1 c = new ChildClass1();
c.CallMethod();

However if "CallMethod" was marked virtual or abstract and overridden in the child class both the above things would call ChildClass1.CallMethod.

So basically i think you're going about your code the completely wrong direction ;) In fact, i'd nearly say that you're screwing yourself over by worrying about allocating an extra 4 bytes of data. The GC can deal with tens of thousands of objects without much problem. Don't screw your design into a nasty mess of bizarre inheritance just so you can use static variables everywhere to 'avoid' allocating.
Mutant_Fruit at 2007-11-9 11:40:56 >
# 9 Re: Get value of static member of class of current instance in inherited method
I've expanded on my suggestion above :

public class NameAttribute : Attribute
{
private string _name;

public NameAttribute(string name)
{
_name = name;
}

public string Name
{
get
{
return _name;
}
}
}

public class NameAttributeHelpers
{
public static string GetName(Type type)
{
NameAttribute[] names =
type.GetCustomAttributes(typeof(NameAttribute), false) as NameAttribute[];

return names[0].Name;
}
}

public class Base
{
public void DoSomething()
{

}

public string Name
{
get
{
return NameAttributeHelpers.GetName(this.GetType());
}
}
}

[Name("Name1")]
public class Child1 : Base
{

}

[Name("Name2")]
public class Child2 : Base
{
}

public class GenericOutput<GClass>
{
static public string StaticName
{
get
{
return NameAttributeHelpers.GetName(typeof(GClass));
}
}

public string InstanceName
{
get
{
return NameAttributeHelpers.GetName(typeof(GClass));
}
}
}

class Program
{
static void Main(string[] args)
{
Base child1 = new Child1();
Base child2 = new Child2();
Console.WriteLine(child1.Name);
Console.WriteLine(child2.Name);

GenericOutput<Child1> output = new GenericOutput<Child1>();
Console.WriteLine(output.InstanceName);
Console.WriteLine(GenericOutput<Child1>.StaticName);
}
}

It includes examples of how to use it in generics.

Darwen.
darwen at 2007-11-9 11:41:54 >
# 10 Re: Get value of static member of class of current instance in inherited method
andreasblixt:

Your second code example doesn't make any sense either. Using "new" rather than overriding should only really be done when you *can't* override. The reason being that a "new" method will only be called if your class is cast to that exact type.

For example:
BaseClass c = new ChildClass1();
c.CallMethod();

will call a completely different method than
ChildClass1 c = new ChildClass1();
c.CallMethod();

However if "CallMethod" was marked virtual or abstract and overridden in the child class both the above things would call ChildClass1.CallMethod.

So basically i think you're going about your code the completely wrong direction ;) In fact, i'd nearly say that you're screwing yourself over by worrying about allocating an extra 4 bytes of data. The GC can deal with tens of thousands of objects without much problem. Don't screw your design into a nasty mess of bizarre inheritance just so you can use static variables everywhere to 'avoid' allocating.

Exactly, I had to use new because you can't override a static member. I didn't use new (I used override) on non-static members, then I would get the effect you're describing. And yes, I left the idea of static properties pretty quickly because of the lack of inheritance.
andreasblixt at 2007-11-9 11:42:56 >
# 11 Re: Get value of static member of class of current instance in inherited method
I've expanded on my suggestion above :

[...]

It includes examples of how to use it in generics.

Darwen.

Darn, that's getting pretty complicated! I think I'll sacrifice that slight convenience of being able to call the properties statically for the sake of simpler code. Right now I have to create one extra instance (I could even recycle it if I wanted to) when loading a table from the database, and it's internal so once the library is in use it won't be in the way anyways.

Now that I've got the attention of someone who's obviously been coding C# for a long time, I'd like to ask you something else: Is there no way to make the compiler resolve a type parameter based on inheritance? I guess that sentence made as much sense as the title of this topic, so again, I'll explain it with code:

class Row<T>
{
// Note: The T represents the value type of a key column; some tables have int, others have short, and on occasion they might have string.
}

class Customer : Row<int>
{
// ...
}

class RowCollection<U> where U : Row<T>
{
// Note: The U is the class that represents a single row.
}

class CustomerCollection : RowCollection<Customer>
{
// Note: This class is not related to my problem, but it gives an idea of how I intend to use this library.
}

The compiler will give an error, telling me that the T in the constraint is not a recognized type name. The type name can however be reliably resolved at compile time, because if U inherits from Row<T>, you can be 100% sure that the definition of U (Customer) has something filled in for T, or it wouldn't compile at that point.

Right now I've solved it by sending along the T with the collection too, but it's getting pretty messy. Especially when I'm implementing relation-based collections:

abstract class RowSubCollection<T, U, V, W> : RowCollection<T, U>
where U : Row<T>
where W : Row<V>
{
// ...
}

I know it looks ugly but don't worry, the user won't have to deal with generics at all. I just wish I could make it simpler for me.
andreasblixt at 2007-11-9 11:44:06 >
# 12 Re: Get value of static member of class of current instance in inherited method
I think you're falling into the trap which I've seen a lot of people fall into with generics : you're using them all over the place.

The trouble with generics is the fact that as soon as you start to use them, you end up having to use them all the time and then your code becomes horribly messy. As you're discovering.

Personally I only use generics for simple things : if I can use interfaces/inheritance then I'd much rather use this than generics for simple readability.

And I've never considered casting to cause anything more than a tiny performance hit in anything I've done so I prefer to keep things simple.

Generics make sense to me for things like collections where you would use 'object' in .NET 1.1, which leads to confusion about what collections contain. But I've only ever found a few cases where I had to use generics in preference to inheritance/casting.

I prefer to keep things simple : so except for using the generics collections and a few other things I don't use generics.

Darwen.
darwen at 2007-11-9 11:45:04 >
# 13 Re: Get value of static member of class of current instance in inherited method
I think you're falling into the trap which I've seen a lot of people fall into with generics : you're using them all over the place.

The trouble with generics is the fact that as soon as you start to use them, you end up having to use them all the time and then your code becomes horribly messy. As you're discovering.

Personally I only use generics for simple things : if I can use interfaces/inheritance then I'd much rather use this than generics for simple readability.

And I've never considered casting to cause anything more than a tiny performance hit in anything I've done so I prefer to keep things simple.

Generics make sense to me for things like collections where you would use 'object' in .NET 1.1, which leads to confusion about what collections contain. But I've only ever found a few cases where I had to use generics in preference to inheritance/casting.

I prefer to keep things simple : so except for using the generics collections and a few other things I don't use generics.

Darwen.

I wouldn't say I've fallen for any trap. Implementing generics internally has decreased the amount of code and normalized it into one class so that I don't have to do a lot of maintenance on 6-7 different classes. The library I'm doing is pretty big and the 2-3 generic classes I intend to have are in no way "all over the place".

I understand it looks daunting with a generic class that has 4 type parameters, but it should really only be looked as 2 type parameters, but the 2 others seem to need to be explicitly specified (this was my question - can I avoid explicitly specifying them?).

And they don't make things more complicated because they're only internal helper classes which the actual classes anyone using the library would use inherit from (see Customer and CustomerCollection in my example). So as I said, the user won't even notice the use of generics.

So to summarize:
+ I've crammed code repeating across 6-7 classes into one helper class, and have managed to shorten those 6-7 classes by a considerable amount.
+ Putting code in one place speeds up maintenance greatly as the same logic doesn't have to be changed for each class.
- Getting into the inner workings of the library for a new developer could take a while longer because of the crazy <T, U, V, W> generic class, even if I've documented it all well.

Anyways, no suggestions for how to turn <T, U> into <U> and <T, U, V, W> into <U, W>?
andreasblixt at 2007-11-9 11:46:00 >
# 14 Re: Get value of static member of class of current instance in inherited method
abstract class RowSubCollection<T, U, V, W> : RowCollection<T, U>
where U : Row<T>
where W : Row<V>
{
// ...
}

Could you not just do:

abstract class RowSubCollection<T, Row<T>, V, Row<V>> : RowCollection<T, U>
{
// ...
}

Or something like that.
Mutant_Fruit at 2007-11-9 11:47:07 >
# 15 Re: Get value of static member of class of current instance in inherited method
Nah, that's a compile error. Besides, it's the T's and V's (key type which is already declared in DBRow<T>, i.e. string, int, short etc) I want to go away.
andreasblixt at 2007-11-9 11:48:00 >
# 16 Re: Get value of static member of class of current instance in inherited method
I'm confused now. I thought you wanted to be able to declare your class without the two extra parameters. Does what i wrote not fill that need? While the code i gave does not compile, it was supposed to illustrate a point. The point was that the U and W parameters are a waste of time considering you've constrained U to be Row<T> and W to be Row<V>.
Mutant_Fruit at 2007-11-9 11:49:04 >
# 17 Re: Get value of static member of class of current instance in inherited method
Now I'm confused too! I can't skip the type parameters altogether because I use them in the derived class, and removing the T and V from the type parameter collection (which is what I wanted to do) results in a compile error because it doesn't understand where T and V come from, even if I have the constraints right there, as you said:

public abstract class RowSubCollection<U, W> : RowCollection<V, W> // Line 18
where U : Row<T>, new()
where W : Row<V>, new()

RowSubCollection.cs(18,66): error CS0246: The type or namespace name 'V' could not be found (are you missing a using directive or an assembly reference?)
RowSubCollection.cs(19,23): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)
RowSubCollection.cs(20,23): error CS0246: The type or namespace name 'V' could not be found (are you missing a using directive or an assembly reference?)
RowSubCollection.cs(81,25): error CS0246: The type or namespace name 'V' could not be found (are you missing a using directive or an assembly reference?)
RowSubCollection.cs(104,28): error CS0246: The type or namespace name 'V' could not be found (are you missing a using directive or an assembly reference?)

If you'd like to have a peek at the library, I've uploaded a tiny sample project here: http://mezane.org/Database.zip

If you want to run it, you'll need SQL Server 2005. I've included an SQL-file to create the database with.
andreasblixt at 2007-11-9 11:50:03 >
# 18 Re: Get value of static member of class of current instance in inherited method
public abstract class RowSubCollection<U, W> : RowCollection<V, W> // Line 18
where U : Row<T>, new()
where W : Row<V>, new()

What is it you want? If you have a RowCollection<int, float>, you want a RowSubCollection<int, Row<int>, float, Row<float>> ? Is that what you want?
Mutant_Fruit at 2007-11-9 11:51:08 >
# 19 Re: Get value of static member of class of current instance in inherited method
I guess it's hard to explain. If you look at the class diagram in the .zip file in my last post maybe it'll help a bit.

Here's a list of all the classes relevant to my problem. It's RowCollection (and consequently RowSubCollection) that I want to change. Look at RowCollection and CustomerCollection for how I seem to have to use and and how I want to use it.
// Represents one row in any table. T is the type of the primary key.
public abstract class Row<T>
{
// ...
}

// Represents one row in the Customers table.
public class Customer : Row<int>
{
// ...
}

// Represents a collection of Row objects (i.e. a set of rows, a record set).
// The T type parameter is specified in the RowCollection type parameter
// list when it (theoretically) doesn't have to be, because it's specified by
// whatever U is (since it has to be or derive from Row<T> where T has to
// be defined as a concrete type).
public abstract class RowCollection<T, U> : ICollection, IEnumerable
where U : Row<T>
{
// ...
}

// This is how I currently have to define CustomerCollection.
public class CustomerCollection : RowCollection<int, Customer> { }

// ---

// Here's what I want (I've removed T from the RowCollection type
// parameter list):
public abstract class RowCollection<U> : ICollection, IEnumerable
where U : Row<T>
{
// ...
}

public class CustomerCollection : RowCollection<Customer> { }

Look at the last definition of CustomerCollection. Here's what I would have expected to happen:
CustomerCollection derives from RowCollection<U>.
U must derive from Row<T> (where T is not yet determined).
U is resolved by Customer.
Customer derives from Row<T> - it passes the constraint.
T is resolved by int, which determines T.

With the above constants, we can resolve the RowCollection class definition that CustomerCollection derives from:
public abstract class RowCollection<Customer> : ICollection, IEnumerable
where Customer : Row<T => int>
{
// ...
}

I think the reason it fails is because in order to resolve T, a second pass must be done. But since this is at compile time, I see no reason for it not to do it.
andreasblixt at 2007-11-9 11:52:08 >