generic class and generic methods - c#

class test <T> where T : class
{
public void Write<T>()
{
Console.Write(typeof(T).FullName);
}
}
In the above class, it is possible to pass in a string for the class (test<string> Test = new test<string>) and then int for the method? If so, what is the output? If not, what problems does this cause? I haven't actually tried this, despite using generics (in my own classes) and generic collections, frequently.
The way I write/see generic classes is as follows:
class <T> where T : class
{
public T Write()
{
Console.Write(T.ToString());
}
}

As it was originally written no you cannot. In order to use different types at different points in the class, you must have multiple generic parameters. It is possible to define a different one at the method level and get your sample to work
class Test<T> where T : class {
public void Write<U>(U arg1) {
Console.WriteLine(arg1.ToString());
}
}
Usage
var t = new Test<string>();
t.Write(42);
As Scott pointed out you can use the same named parameter. Although doing so will cause a warning and generally speaking confuse people. It is much cleaner to have distinct names for all generic parameters currently in scope.

You'll be wanting to declare a type variable in the method separately to the class -
class Test<T> where T : class {
public void Method<U>(U val) {
Console.WriteLine(typeof(U).FullName);
}
}

Related

Override function from base class with a different enum

Okay, the title may sound a bit confusing, just read my explanation here to understand what I mean:
I got a base class, lets call it BaseProvider. This class looks like this:
public abstract class BaseProvider
{
public abstract void NewItem(int type);
}
Now I add a second class that derives from the BaseProvider. Lets call it TestProvider:
public class TestProvider : BaseProvider
{
public override void NewItem(int type)
{
}
}
Okay, now here comes my question / problem:
As there are different sub-types that this provider should be able to handle, I created the parameter int type. However it would be much nicer to be able to use Enums. And as every data provider will have a different set of sub-types I can't reuse a already existing one.
Now my method signature has to match exactly the one from the base class which makes it impossible to change the parameter type to an enum (even though an enum is basically an int).
I did try to define my deriving class like the following:
public class TestProvider : BaseProvider
{
public override void NewItem(MyEnum type)
{
}
}
enum MyEnum : int
{
TEST = 1
}
As excpeted this does not work...
So my question now is:
Is it possible to overwrite a base function with a different parameter type that derives from the parameter type defined in the base class? If yes how?
No, absolutely not - and here's why... This code still has to work:
BaseProvider provider = new TestProvider();
provider.NewItem(10);
That's just the normal requirements of polymorphism. You can't change a signature when you're overriding, because callers may be considering your instance in terms of the base class instead. (Indeed, if they're not doing so, why bother having the abstract method at all?)
Now you can overload the method:
public override void NewItem(int type)
{
NewItem((MyEnum) type);
}
public void NewItem(MyEnum type)
{
...
}
That's not quite the same thing, but it probably achieves what you want.
Alternatively, you could make BaseProvider generic:
public abstract class BaseProvider<T>
{
public abstract void NewItem(T type);
}
public class TestProvider : BaseProvider<MyEnum>
{
public override void NewItem(MyEnum type)
{
}
}
You are actually missing out the concept of overriding here. It is not about changing method definition. It is about changing method behavior. What you could do here is either overload, or make sure you cast your enum as int before call.

C# Using generics and interface implementation

Context: .NET 4.0, C#
I'm creating a set of interfaces and a set of clases that implement them to provide some service. The clients use the concrete clases but call methods that are declared using the interfaces as parameter types.
A simplified example is this one:
namespace TestGenerics
{
// Interface, of fields
interface IField
{
}
// Interface: Forms (contains fields)
interface IForm<T> where T : IField
{
}
// CONCRETE CLASES
class Field : IField
{
}
class Form <T> : IForm<T> where T : IField
{
}
// TEST PROGRAM
class Program
{
// THIS IS THE SIGNATURE OF THE METHOD I WANT TO CALL
// parameters are causing the error.
public static void TestMethod(IForm<IField> form)
{
int i = 1;
i = i * 5;
}
static void Main(string[] args)
{
Form<Field> b = new Form<Field>();
Program.TestMethod(b);
}
}
}
The code makes sense to me, but I get the compiler error:
Argument 1:
cannot convert from 'TestGenerics.Form<TestGenerics.Field>' to
'TestGenerics.IForm<TestGenerics.IField>' TestGenerics
I'm not sure what I'm doing wrong, I've read lots of pages on the internet but none solved my problem.
Is there a solution that would not modify that much the architecture of what I'm trying to build:
Edit:I designed the interfaces in a way such that they should be independent of concrete clases that implement them. The concrete clases could be loaded from a dll, but most of the application Works with the interfaces. In some cases I need to use concrete clases, specially when using clases that need to be serialized.
Thanks in advance.
Alejandro
The problem is that Form<Field> implements IForm<Field> but not IForm<IField>. You cannot use an inherited class (or interface) as a generic parameter unless it is marked as covariant with the out identifier. However, marking your interface as covariant will restrict the usage significantly (basically making in an "output-only" interface like IEnumerable) so it may not work for you.
One way to get it to work is to make TestMethod generic as well:
public static void TestMethod<T>(IForm<T> form) where T:IField
{
int i = 1;
i = i * 5;
}
You can use Covariance, like so:
interface IForm<out T> where T : IField
{
}
More about Covariance and Contravariance here.
Others have pointed out the reasoning behind the error message, but let's examine the design of your sample code for a moment. Perhaps you're using a generic where none is needed.
You've already said you're using methods declared in the IField interface, so there may be no need to make your IForm class generic - simply have it store references to IField, instead of the generic argument 'T' (which is already guaranteed to be an IField anyway).
For instance, use:
public interface IForm
{
IEnumerable<IField> Fields { get; set; }
}
instead of
public interface IForm<T> where T : IField
{
IEnumerable<T> Fields { get; set; }
}

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.

Dealing with multiple generics in a method call

I've been dealing a lot lately with abstract classes that use generics. This is all good and fine because I get a lot of utility out of these classes but now it's making for some rather ugly code down the line. For example:
abstract class ClassBase<T>
{
T Property { get; set; }
}
class MyClass : ClassBase<string>
{
OtherClass PropertyDetail { get; set; }
}
This implementation isn't all that crazy, except when I want to reference the abstract class from a helper class and then I have to make a list of generics just to make reference to the implemented class, like this below.
class Helper
{
void HelpMe<C, T>(object Value)
where C : ClassBase<T>, new()
{
DoWork();
}
}
This is just a tame example, because I have some method calls where the list of where clauses end up being 5 or 6 lines long to handle all of the generic data. What I'd really like to do is
class Helper
{
void HelpMe<C>(object Value)
where C : ClassBase, new()
{
DoWork();
}
}
but it obviously won't compile. I want to reference ClassBase without having to pass it a whole array of generic classes to get the function to work, but I don't want to reference the higher level classes because there are a dozen of those. Am I the victim of my own cleverness or is there an avenue that I haven't considered yet?
I suppose that your HelpMe method would be used for initializing the concrete ClassBase<T> type (a guess based on the constraints). To keep the code fully generic (if you need both T and C somewhere in the method), you probably need to keep both of the type parameters.
However, you could add a non-generic base class and then write something like this:
abstract class ClassBase {
object UntypedProperty { get; set; }
}
abstract class ClassBase<T> : ClassBase {
T Property { get; set; }
public override object UntypedProperty {
get { return Property; }
set { Property = (T)value; }
}
}
Then you could be to write the helper method like this:
void HelpMe<C>(object Value) where C : ClassBase, new() {
var n = new C();
c.UntypedProperty = Value;
}
Depending on your specific scenario, something along these lines might work and make the code a little bit simpler. However, you need to modify the base class to make this possible.
Generics do have a tendency to propogate through the code, and they're seldomly used as "mixin" classes for that reason.
Thomas mentioned the one possibility of introducing an equivalent non-generic API. I would prefer revisiting the design and making these base classes non-generic if possible while maintaining full type safety. Whether or not this is actually possible is determined by your requirements.
There is one other possibility short of a re-design (or API duplication): dynamic. If you're willing to lose IntelliSense in your helper methods (and are willing to pay a very, very small runtime performance penalty), you can use dynamic in your helper method:
class Helper
{
void HelpMe<C>(object Value)
// where C : ClassBase<T>, new() // no longer needed, but should be documented
{
dynamic cObj = Activator.CreateInstance<C>(); // instead of "new C()"
cObj.PropertyDetail = ...;
cObj.Property = ...;
...
}
}
without having to pass it a whole array of generic classes to get the function to work
A small change might ease these calls. Move repeatedly specified types to the generic declaration of the class.
//before
Helper x = new Helper();
x.HelpMe<MyClass, string>(x);
x.HelpMe<MyClass, string>(y);
//after
Helper x = new Helper<string>();
x.HelpMe<MyClass>(x);
x.HelpMe<MyClass>(y);
//the change
class Helper<T>
{
void HelpMe<C>(object Value)
where C : ClassBase<T>, new()
{
DoWork();
}
}

generic inheritance in C#? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?
I can do
public class MyGenericClass : DL
//but i cannot do
public class MyGenericClass <T> : T
How would i do the second? if i cannot do that, how can i do something like
public class MyGenericClass <T>
{
T obj;
//have all MyGenericClass.XYZ call obj.XYZ
}
This is not possible, because depending on what type T is, the public interface of MyGenericClass would change.
If you have lots of different classes that all expose the same interface, you could declare MyGenericClass to expose that interface, and in the implementation of all of the functions delegate the calls to obj
The specific question, why can't you do this:
public class MyGenericClass<T> : T
And you can do this:
public class MyGenericClass<T>
{
T obj;
}
The reason is that the CLR likes to be able to compile a single version of the code for MyGenericClass that will work for any reference type specified for T.
It can do this for the second case, because it can quietly replace T with object and insert appropriate casts, roughly equivalent to:
public class MyGenericClass
{
object obj;
}
But for the inheritance version, that trick doesn't work.
Also, many useful facilities would be impossible to describe through interface constraints. When you inherit from a type, you can do a lot more than just call methods on it - you can override them as well. Consider this hypothetical example:
class MyBase
{
public virtual void MyVirtual() { }
}
class MyGenericDerived<T> : T
{
public override void MyVirtual()
{
Console.WriteLine("Overridden!");
}
}
MyBase obj = new MyGenericDerived<MyBase>();
obj.MyVirtual();
What I want to do there is something like a "mix-in", where MyGenericDerived supplies definitions for virtual functions in whatever base it is applied to. But how does the compiler know that T will have a method called MyVirtual that can be overridden? I'd need to put a constraint on T. How would I express that through interfaces? It's impossible. Using interfaces to describe constraints isn't an adequate solution once you allow inheritance from type parameters. So that's another reason why it doesn't exist in the language today.
You could do something like
public interface IXyzable { void xyz(); }
public class MyGenericClass<T> : IXyzable where T : IXyzable {
T obj;
public void xyz() {
obj.xyz();
}
}
Edit: Now I understand the question
You'll need all your possible T's to implement some interface so that you know that obj.XYZ() makes sense, then you can do
public interface Ixyz
{
void XYZ();
}
public class MyGenericClass<T> : Ixyz where T:Ixyz, new()
{
T obj;
public MyGenericClass()
{
obj = new T();
}
public void XYZ()
{
obj.XYZ();
}
}
I've made MyGenericClass implement Ixyz too since it obviously does expose the right method, but maybe that's best left out since it allows
var x = new MyGenericClass<MyGenericClass<SomeClass>>();
which is unlikely to ever be a good idea.
This is pretty much duck-typing, but you could use reflection.
When you create the generic class with a reference to the obj, use reflection to try and find a method with the right signature. As long as you store a reference to the method, performance won't be too bad.
class BaseGeneric<T>
{
private T obj;
private MethodInfo mi;
private const string MethodNameOfInterest = "Xyz";
public BaseGeneric(T theObject)
{
this.obj = theObject;
Type t = obj.GetType();
mi = t.GetMethod(MethodNameOfInterest);
}
public void Xyz()
{
mi.Invoke(obj, null);
}
}
Of course, you would need to add a lot more for error checking and such, but that is the gist of what you could do. Also, don't forget to add the System.Reflection namespace to your using clause.
The .NET type system won't allow type declarations of the form you're attempting. One reason why this is disallowed should be intuitive: how would MyGenericClass<T> act when T is a sealed class (e.g. System.String)?
If you absolutely need this functionality (and you know that the type T you'll be using isn't sealed), you can generate proxies at runtime using the classes in the Reflection.Emit namespace. It may also be possible to achieve this effect using AOP tools like PostSharp.
What about this:
class BaseClass<T>
{
public T property { get; set; }
}
class GenericClass<T> : BaseClass<T>
{
}
class Program
{
static void Main(string[] args)
{
GenericClass<int> l = new GenericClass<int>();
l.property = 10;
}
}
This achieves what you want to do?

Categories