Static methods on generic classes? - c#

Okay, this is the case:
I got a generic base-class which I need to initialize with some static values. These values have nothing to do with the kind of types my generic baseclass is loaded with.
I want to be able to do something like this:
GenericBaseclass.Initialize(AssociatedObject);
while also having a class doing like this:
public class DerivedClass : GenericBaseclass<int>
{
...
}
Is there any way to accomplish this? I could make a non-generic baseclass and put the static method there, but I don't like that "hack" :)

If the values have nothing to do with the type of the generic base class, then they shouldn't be in the generic base class. They should either be in a completely separate class, or in a non-generic base class of the generic class.
Bear in mind that for static variables, you get a different static variable per type argument combination:
using System;
public class GenericType<TFirst, TSecond>
{
// Never use a public mutable field normally, of course.
public static string Foo;
}
public class Test
{
static void Main()
{
// Assign to different combination
GenericType<string,int>.Foo = "string,int";
GenericType<int,Guid>.Foo = "int,Guid";
GenericType<int,int>.Foo = "int,int";
GenericType<string,string>.Foo = "string,string";
// Verify that they really are different variables
Console.WriteLine(GenericType<string,int>.Foo);
Console.WriteLine(GenericType<int,Guid>.Foo);
Console.WriteLine(GenericType<int,int>.Foo);
Console.WriteLine(GenericType<string,string>.Foo);
}
}
It sounds like you don't really want a different static variable per T of your generic base class - so you can't have it in your generic base class.

That's exactly what you have to do. When you have a type parameter, each different instantiation of the type is a separate type. This leads to separate static variables.
The only workaround is to have a base class that the generic class derives from.

Related

Is there a way to restrict access to some methods according to the type passed to a generic class?

I'm currently working on a generic class. I want to restrict accessibility to some methods when passing different types. Let's say it looks something like this:
public class MyGeneric<T>
{
public void Foo1(){}
public void Foo2(){}
}
I obviously can use the typeof operator to implement different behaviours but let's say that Foo1 counts the average of some numbers. If I pass in the type "Student" it can count the average of grades. But let's say I pass in "Car" and I don't want it to do anything. Having it just there and doing nothing with that type would be redundant. Is there a way to completely restrict access to it? Thanks!
You could use abstraction/inheritance for this.
Creating a class
public class MyGeneric<T>
{
public void Foo1(){}
}
which handles all 'global' functions, and then create a child class like this:
public class MyGenericChild<T> : MyGeneric<T> where T : IMyInterface
{
public void Foo2(){}
}
You can then use the specific child to handle the type specific methods.
If needed, you could expand this with a factory-pattern to retreive the correct generic class.

Get derived class properties in base Static method - RIDDLE! :)

I wanted to elaborate on the current project i'm working on but that would be kind long. Instead I'll just post a programming riddle which basically explains what i'm trying to accomplish. :)
abstract class A
{
// key = Derived Class name, value = list of properties the derive class exposes.
private static Dictionary<string, List<string>> _DerivedPropertyNames;
static A()
{
InitializeDerivedPropertyNames();
}
private static void InitializeDerivedPropertyNames()
{
//...???...
}
}
The riddle is how can you create an abstract base class which will hold a static cache of all its derived classes properties?
Note that the idea is to avoid loading an assembly by name.
There is no easy (efficient) way to do this in the base class.
Simply implement a static constructor in every derived class and use it to register the properties.
Also take a look at Dependency properties in the WPF Fx, for comparison.
If you can wait for instances of the child types to be instantiated, then you could use A's regular constructor to register the implementing class:
public A()
{
Type childType = GetType();
string className = childType.Name;
if (!_DerivedPropertyNames.ContainsKey(className)) {
// add properties for this class
}
}
It will be very difficult for you to get the job done in the static constructor, before any instantiation, without adding logic in the child classes (which I suppose you don't want). The reason is that you won't be able to enforce all assemblies containing types that implement A to be loaded when A's static constructor is called.

Inferring C# Generic Type of Subclass

I have a generic class Proxy<T>, and I want to write another generic class with its type parameter being a Proxy.
I want to write:
public class MyClass<U> where U : Proxy<T>
but the compiler reports The type or namespace name T could not be found.
A solution I've found is to declare it like this:
public class MyClass<U, T> where U : Proxy<T>
but this seems clumsy as the client will have to declare two type parameters, like this:
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass> { ... }
and then in a client somewhere:
var proxyWrapper = new MyClass<SomeProxy, SomeClass>();
How can I do this without having to have two generic types on MyClass. After all, if we know the first is SomeProxy, it should follow that the second is SomeClass.
Maybe something like this would do the job, too?
class Test<T> {
public Test(Proxy<T> proxy) { this.MyProxy = proxy; }
public Proxy<T> MyProxy { get; private set; }
}
Sorry, you just can't do this in C# without having MyClass generic on both types (unless you want to use reflection to create instances of it.)
You can have an interface IMyClass<SomeProxy> and a factory method that creates and returns an instance of MyClass<SomeProxy, SomeClass>. You may need to create the instance using Reflection.
I have a code example here of a similar situation: the end user only cares about a single type parameter, but the implementation needs to have two. In my example, I don't have to use Reflection to create the instance, but it sounds like you may need to.
What you're trying to do is possible using compile-time constructs such as C++ templates, but not run-time constructs such as C# generics.
If you want T to remain generic in Myclass, then the MyClass instance still needs to resolve all internally used generic types and you HAVE TO declare it somewhere. The way to go is the verbose way you mentioned:
public class MyClass<U, T> where U : Proxy<T>
If you don't care about the generic type T in MyClass then create interface and use it instead:
public interface IProxy { ... }
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass>, IProxy { ... }
public class MyClass<U> where U : IProxy
and then in a client somewhere:
var proxyWrapper = new MyClass<SomeProxy>();
But do note that you cannot use type T in your interface declaration and Type U is now more general then before.
It turns out that all of the SomeProxy classes I want to deal with actually just override one method of Proxy<T> which has the signature:
T LoadInternal(Identifier id)
So, what I've done is created an internal class inside MyClass which takes a Func<Identifier, T> in its constructor. I can then pass a Func<Identifier, T> as a parameter to the constructor of MyClass and use my subclass in place of SomeProxy.
Seems a bit convoluted, but it works for me. To summarise, I now have:
public class MyClass<T>{
private SomeProxy theProxy;
public MyClass(Func<Identifier, T> loadDelegate){
theProxy = new SomeProxy(loadDelegate);
}
/* Other methods here */
class SomeProxy : Proxy<T>{
private Func<Identifier, T> m_loadInternal;
public SomeProxy(Func<Identifier, T> loadInternal){
m_loadInternal = loadInternal;
}
protected override T LoadInternal(Identifier id){
return m_loadInternal(id);
}
}
}
So, from client code, instead of writing a class which extends Proxy and then overriding LoadInternal in that class, I just create MyClass using:
var myClass = new MyClass<T>(x => CodeWhichReturnsT());
How can I do this without having to have two generic types on MyClass. After all, if we know the first is SomeProxy, it should follow that the second is SomeClass.
Although you seem to have found an answer to the main part of the question, I figured I'd offer my understanding about this part. It sounds like you wish you could do something like this:
class Proxy<T>
{
T Value { get; set; }
}
class MyClass<U> where U : Proxy<> { }
and have the compiler fill in the Proxy type parameter when you provide U. Since you have declared U as inheriting from Proxy, you must intend to use one of the methods on Proxy, that probably use the T parameter, like so:
class MyClass<U> where U : Proxy<>
{
void SomeMethod(U parameter)
{
var local = parameter.Value;
//more code here...
}
}
Now, what is the compiler supposed to infer for local here? This is the main problem I see that makes such a feature, if possible, hard to implement. If you don't want to use any methods that use the generic type of Proxy, you could instead make a non-generic base class and use that for U and sidestep the entire problem.
I am not a compiler writer, but a couple possibilities of how this could be dealt with come to mind. It could just say object (or whatever other restriction you put on the type parameter in Proxy), but that doesn't seem quite right or quite what normal generics seem to do. This would also require the CLR to allow open generic types as a constraint on the generic parameter, which I doubt it does. The other option I could see is for the type to actually have the second type parameter, and the compiler to give you syntactic sugar to make it easier.
Any way you go, this feature seems like a lot of work for a little benefit in what is probably a rare scenario, thus not likely to make the cut to get implemented.

Return MyNestedClass<K> when MyNestedClass is not MyNestedClass<K>?

Breaking down the MS RBTree (an internal .Net abstract class), I have discovered that one method returns TreePage<K>:
private TreePage<K> AllocPage(int size)
{
...
}
Within the method, variables are declared as TreePage...but the class is not defined that way:
private sealed class TreePage
{
...
}
Yet, when I mimic the code and definition using .Net 2010 (Express), I cannot do this:
Error: The non-generic type
'RBTree.TreePage' cannot be used
with type arguments
So, is there an extension method that I can't find? Is there something MS is doing that we just don't get to see?
When you declare a class nested in a generic class
class Foo<T>
{
class Bar
{
}
}
this gets compiled to a class
Foo<T>
and a class
Foo+Bar<T>
Bar is generic, because it is nested in the generic class Foo. But the type parameter declaration is not repeated in C# (where you refer to the class as Foo<T>.Bar).
I noticed that Reflector shows the generic type parameter for classes nested in generic types, even if they don't have declared any type parameters directly. That's a bug. You need to fix the code when copy it straight out of Reflector.
It's actually less complicated than you might imagine. Klass and Klass<T> are two completely different types. To wit:
class A
{
}
class A<T>
{}
class Program
{
static public void Main(string[] args)
{
A a = new A();
A<int> generic_a = new A<int>();
}
}
There's another TreePage<T> floating around there somewhere.

Why does a static method on a generic type require a Type parameter?

public class BinarySearchTree<T>
where T : IComparable<T>
{
public static BinarySearchTree<char> InitializeSampleCharacterBST()
{
var bst = new BinarySearchTree<char>();
bst.Insert('F');
bst.Insert('B');
bst.Insert('A');
bst.Insert('D');
bst.Insert('C');
bst.Insert('G');
bst.Insert('I');
bst.Insert('H');
return bst;
}
class Program
{
static void Main(string[] args)
{
var bst = BinarySearchTree.InitializeSampleCharacterBST();
}
}
Why is this illegal? It's expecting me to provide a type parameter to the method call for the class which makes no sense. A generic class or method has no use for a type parameter in a static context.
It wants me to write the call like this:
var bst = BinarySearchTree<foo>.InitializeSampleCharacterBST();
Where foo can be any type I want regardless of the fact that the static method call returns a specifically typed generic object.
the class BinarySearchTree and BinarySeachTree<Foo> are completely separate; the language allows generic type overloading. Perhaps declare this method on a non-generic twin class:
public static class BinarySearchTree {
public static BinarySearchTree<char> InitializeSampleCharacterBST() {...}
}
public class BinarySearchTree<T> {...} // rest of the code
Otherwise... what T would it use? And what if the static method talked to static fields? Let alone which T to use, each T gets different static fields (i.e. SomeType<Foo> has separate fields to SomeType<Bar>).
As Marc said, it's sometimes useful to overload the type to have a non-generic class - and it would be in this case.
As for why it's necessary, suppose that the static method were actually implemented as:
public static BinarySearchTree<char> InitializeSampleCharacterBST()
{
Console.WriteLine(typeof(T));
return null;
}
That would be perfectly valid code - it's in a generic type, so it should have access to the type parameter... but you're trying to call the method without providing a generic type parameter, so it couldn't possibly work. In your case you happen to not use T anywhere within the method, but that's a coincidence. It's a bit like having an instance method which doesn't use this: you're not using the instance, but you still can't call it as if it were a static method.
As well as having separate static classes, another design technique which can be useful is to split your type into non-generic and generic pieces. That way, in cases where it can be awkward to work out which exact type you have, you don't actually need to know it in order to call some of the members. For example, a collection interface hierarchy might have:
public interface ISomeCollection
{
int Count { get; }
void Clear();
}
public interface ISomeCollection<T> : ISomeCollection
{
void Add(T item);
}
I've used this technique myself for my Protocol Buffers port to C#, and it's proved very useful (if somewhat complicated).
You're forgetting that type parameters don't only appear in the parameter/return type of a method. They can also appear in the implementation:
public static BinarySearchTree<char> InitializeSampleCharacterBST()
{
var forSomeReason = new T();
By placing your method inside a static class with a type parameter, you are saying that the implementation of the method may (now or in some future revision) depend upon that type parameter.
If this isn't the case, you've put the method in the wrong place.
Because the type itself is Generic, you have to provide a type argument, even if the static method you are interested in does not make use of that type argument. Its just the nature of generics in C#...they don't exist in a non-generic form at any time. If they did, that would cause conflicts with a non-generic version of the same type.

Categories