Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# .NET C#4.0 VB.NET .NET4
I have a little problem with Generics.
I think I already know the answer and if that is the case I am bummed out. But hopefully some of you can prove me wrong Smile | :)
 
I have some Generic Interfaces and some Generic Class Implementations.
The problem is that I need Attributes, and Attributes cannot handle Generics!
So I have no way of knowing what <T> is for my Interface and Classes. Instead I have my Interface<T> derive from a non-Generic Interface... Unfortunately the non-Genericness is slithering through my Class structure like a non-Generic snake!
I have already made good working Classes that use my Generic Interfaces and they are usable also without the Attributes. So dropping Generics alltogether is no option.
Is there a way however to convert a BaseInterface to a DerivedInterface<T>? Is this also possible when you only know T at runtime?
Something like DerivedInterface<myVar.GetType()>?
 
My question may be a bit cryptic in the late evening, so if I am not clear enough do not hesitate to ask Smile | :)
Thanks!
 
Edit after next edit:
After really close re-re-re-re-consideration of my code I have concluded that my design is busted (yes, even I make mistakes Poke tongue | ;-P )! I do need not to cast from IDerived<int> to IDerived<Object>. However I would still like to know if it is possible.
 
Edit:
Thanks to SAKryukov for a very detailed answer! It really helped! Smile | :)
After having a good night sleep and reading SAKryukovs answer I can now put my question into better words than last night though. So here it goes again.
In the following code snippet, which closely matches my own scenario, I must convert a Something<int> to a Something<Object>. The way I see it is that int is an Object so this conversion should be no problem. Wrong!
As SAKryukov put it (and he should correct me if I am wrong) it is because Something<int> is the type of Something<int> (and not Something and then an int or a Generic Something). And even though int Inherits from Object Something<int> does not Inherit from Something<Object>.
class Program
{
	static void Main(string[] args)
	{
		DerivedSomething thing = new DerivedSomething();
		if (CheckMustStop<int>(thing))
		{
			Console.WriteLine("Stop!");
		}
		else { Console.WriteLine("Don't stop!"); }
		Console.ReadKey();
	}
 
	static bool CheckMustStop<t>(Something<t> thing)
	{
		// This is where stuff gets nasty!
		// An int is an Object, but casting will not work!
                // Mind you that I know T is an int. In my own code I do not know this.
		Something<Object> tempThing = (Something<Object>)thing;
		return tempThing.MustStop;
	}
}
 
public class DerivedSomething : Something<int>
{
	public void DoSomething(int item)
	{
		// Do stuff here, <t> is important for item.
	}
		public bool MustStop
	{
		// <t> does not matter!
		get { return true; }
	}
}
 
public interface Something<t>
{
	void DoSomething(T item);
	bool MustStop { get; }
}
As you see it does not matter which type T is in the example. Because no matter which type T is it will always have a MustStop Property which does not care about the type of T. This leads me to believe that Something<T> actually needs a non-Generic base Interface to be able to check if Something<T> of whatever type must stop.
Such as this:
public interface Something<t> : Something
{
	void DoSomething(T item);
}
 
// I can always cast to Something without knowing the type of T!
public interface Something
{
	void DoSomething(Object item);
	bool MustStop { get; }
}
This creates new problems, such as Something only being usable on its own when it has a non-Generic DoSomething Method and the fact that I need a non-Generic base Interface for almost all my Generic Interfaces. Which really tends to clutter up code Smile | :)
 
I hope this further clarifies my problem. Any help is greatly appreciated Smile | :)
Posted 15-Oct-11 11:46am
Edited 15-Oct-11 23:50pm
v5
Comments
BillWoodruff at 15-Oct-11 21:09pm
   
I ... kind of ... get what you are asking here, and it's a fascinating question (which I just hi-fived), one I'd like to know the answer to as well. What would help me, in this case, would be a code example. thanks, Bill
SAKryukov at 15-Oct-11 21:55pm
   
Imagine that -- I've even given pretty comprehensive answer. Please see, hope it's interesting.
I'll also vote 5 for interesting question.
--SA
Naerling at 16-Oct-11 4:48am
   
Thanks for the hi-five! As a response to SAKryukovs fine answer I have actually edited my question in a way that you might too find interesting :)
SAKryukov at 15-Oct-11 21:56pm
   
My 5 for this interesting question, even though it is not 100% clear and not 100% correct. :-)
Hope my answer will give some ideas.
--SA
Naerling at 16-Oct-11 4:46am
   
Thanks for your once again great answer! It did give me some ideas as you can see in my edited question :)
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

If the purpose of the casting is to use members of the derived class, you can use Type.MakeGenericType[^] method, in order to get the actual generic type and, invoke the wanted methods using reflection[^].
  Permalink  
v3
Comments
BillWoodruff at 15-Oct-11 21:15pm
   
Hi-five for this: absolutely fascinating. I hope one day to be able to understand such esoteric use of generics, but, today, I am very far from that goal:) !
Shmuel Zang at 16-Oct-11 16:53pm
   
Thanks.
SAKryukov at 15-Oct-11 22:04pm
   
Very good idea, even though it does not really answer the question (which is about a cast, which is different).
Anyway, such things is very good to know, I voted 5, but -- please see my answer.
--SA
Shmuel Zang at 16-Oct-11 17:19pm
   
Thanks.
Naerling at 16-Oct-11 3:54am
   
Thanks! I didn't know that one. May actually come in handy so my 5 :)
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Very interesting question, even though it is not quite correct.
 
The answer is: of course you can cast from non-generic to generic. But…
Let's try to sort things out.
 
I will try to differentiate some things which look subtle and usually can be ignored, but is the exotic case you're trying to make are important.
 
First of all, BaseInterface to a DerivedInterface<T> are types, and you never convert types. Think about it: you always convert objects.
 
Next step. Type casting in the sense you are talking about is never a conversion. It does not move any data anywhere. It just allows to treat the value of the variable declared as one type as another type. One particular case is down-casting of the variable of the types related as base/derived:
 
class Base {/*...*/}
class Derived : Base {/*...*/}
Base b = new Derived(/*...*/);
Derived d = (Derived)b;
 
It does not matter, classes or interfaces. A class or struct is only needed to have an instance to demonstrate the case. (Important! Note that structures can also implement interfaces — not very well known fact.) Note that this cast is only possible because b has a run-time type which is actually Derived. You can only cast a variable of some compile-time type to the actual run-time type or one of its bases.
 
Finally, realize that. Even though generic type do exist not only during compile time but also during run-time, which can be seen via Reflection, generic types do not exist in objects. By their nature, all objects are always of some fully-instantiated type. You can have an object of System.Collections.Generic.List<string>, never of the generic List type. In makes the problem pretty simple:
 
    interface IBase {
        void BaseOperation();
        //...
    } //interface IBase

    interface IDerived<OPERAND> : IBase {
        OPERAND Sum(params OPERAND[] members);
        OPERAND Product(params OPERAND[] members);
        //...
    } //interface IDerived
    
    abstract class Arithmetic<OPERAND> : IDerived<OPERAND> {
        void IBase.BaseOperation() { }
        OPERAND IDerived<OPERAND>.Sum(params OPERAND[] members) { return ImplementSum(members); }
        OPERAND IDerived<OPERAND>.Product(params OPERAND[] members) { return ImplementProduct(members); }
        protected internal abstract OPERAND ImplementSum(params OPERAND[] members);
        protected internal abstract OPERAND ImplementProduct(params OPERAND[] members);
        protected internal OPERAND SomeAuxMethod() { return default(OPERAND); }
        //...
    } //class Arithmetic
    
    class IntegerArithmetic : Arithmetic<int>, IDerived<int> {
        protected internal override int ImplementSum(params int[] members) {
            int result = 0;
            foreach (int member in members) result += member;
            return result;
        }
        protected internal override int ImplementProduct(params int[] members) {
            int result = 0;
            foreach (int member in members) result *= member;
            return result;
        }
        //...
    } //class IntegerArithmetic

    class Test {
        void TestMethod() {
            IBase @object = new IntegerArithmetic();
            //...
            IDerived<int> integerArithmeticObject =
                (IDerived<int>)@object;
            int sum = integerArithmeticObject.Sum(new int[] {1, 12, 113, });
            //will work!
        }
    } //class Test
 
The main benefit of the method of abstraction shown above is having implementation of some algorithms not depending on concrete type of OPERAND in abstract class Arithmetic represented by the interface IDerived. Those methods are not shown; they can include working with containers of OPERANDS, search, sorting (will need generic constraint to allow comparison operators) and a lot more. Numeric-specific operations a postponed to the classes instantiating generic types. This problems is particularly difficult with numeric types and is much easier when generic parameters are constraint to be classes or (even easier) interfaces.
 
As I can understand, you have "generic" problems with designing your code. Well, I understand, this is natural, even though I don't really understand your problem. The understanding probably requires some sample code. However, I hope that better understanding of combination of generics and OOP could help you to have a fresh look at your problem and improve things. I also hope my simple sample code can give you some ideas.
 
Good luck,
—SA
  Permalink  
v7
Comments
BillWoodruff at 15-Oct-11 22:07pm
   
Hi-Five for this ! I can 'follow' this pretty well; I think the 'sticking point' for me, in this 'knowledge domain,' is connecting these 'powerful ideas' to a sense of: in what scenarios they are particularly useful and appropriate. thanks, Bill
SAKryukov at 15-Oct-11 22:49pm
   
Thank you, Bill.
 
You probably mean combination of OOP and generics... I've used and created such scenarios and can say they can be pretty complex, especially when you design such code, not when you use it. In one word, they are important when you develop a library without knowing all possible uses of it, so you want to make it very flexible... Giving just one sample will hardly help to feel such situations. It would need a really big article.
--SA
Mehdi Gholam at 16-Oct-11 1:05am
   
My 5!
SAKryukov at 16-Oct-11 2:32am
   
Thank you, Mehdi.
--SA
Naerling at 16-Oct-11 4:45am
   
Thanks for a very good and detailed answer! My 5.
This answers part of my question and sets me on the right track. It also helped me to see my real problem.
Which is actually not casting Derived to Base or vice versa, but to cast Derived to a Derived<Base>. See my edited question for details. Any help is greatly appreciated.
If you want to answer please create a new answer (instead of editing this one). This helps me to keep things apart and to vote the other 5 you deserve :)
Or in my case, does not matter. I just want to know if a certain Object is of type SomeClass.
Because the case is that I need to check a non-Generic Property on a Generic Interface.
SAKryukov at 16-Oct-11 15:13pm
   
First of all, I can see a mistake in your question above. Let's see.
If Derived<Base> is class, Derived is a generic class, Derived. An instance cannot have generic type during run-time, so you cannot want to cast from one to another. You probably mean something else.
Your edit of main question is different...
--SA
Shmuel Zang at 16-Oct-11 17:03pm
   
Nice explanation. I voted 5.
Espen Harlinn at 16-Oct-11 17:32pm
   
Excellent effort, Sergey - obviously this deserves a 10, but as that's not possible you have my 5+ :)
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

As requested, I'm answering an edited version of the question is a separate answer. This question is indeed radically different from the original question. Smile | :)
 
All the problem is the misuse of the non-generic method of generic interface. Here is how a fixed version of the code might look (and it will work, of course):
 
public class DerivedSomething : ISomething<int> {
    public void DoSomething(int item) {
        // Do stuff here, <T> is important for item.
    } //DoSomething
    public bool MustStop {
        // <T> does not matter!
        get { return true; }
    } //MustStop
} //class DerivedSomething

public interface ISomething<T> {
    void DoSomething(T item);
    bool MustStop { get; }
} //ISomething<T>

class Test {
    void TestMethod() {
        DerivedSomething thing = new DerivedSomething();
        if (thing.MustStop)
            Console.WriteLine("Stop!");
        else
            Console.WriteLine("Don't stop!");
    } //TestMethod
} //class Test
 
I also renamed Something to ISomething to meet (good) Microsoft naming conventions for interfaces. There is certain confusion due to the fact you miss one important step which partially defeats the purpose of generic interfaces. To make the inheritance chain really practical, you need to make is like this: generic interface => generic (possibly abstract) class implementing methods agnostic to generic parameters => set of complete implementation classes — using the idea shown in my previous answer. The term "class" could be replaces with "struct".
 
[EDIT #1]
 
This is amazing: I just made a real "Freudian slip" (http://en.wikipedia.org/wiki/Freudian_slip[^])!
 
In the above paragraph, I wanted to type "(good) Microsoft naming conventions", but typed "goof Microsoft naming conventions"!
 
No, they are really good, not goof; and I'm using them.
 
[END EDIT #1]
 
[EDIT #2]
 
After some thinking, I realized that I can see two more problems in the code above. I explained above, that 1) missing intermediate implementation class implementing just non-generic part of the interface; in this way you would not repeat implementation of those non-generic methods/properties in each of generic type-specific implementation. Two remaining problems are: 2) interfaces are designed to be use during run-time; remove all interfaces from your code — it will work in exact same way, why writing them? you should really use your classed via interfaces; 3) you use implicit interface implementation (via "public"); but explicit interface implementation is much clearer.
 
My fix of the problems (2) and (3) required change in usage but then the use of interfaces is really justified in a practically beneficial way, and lack of code reuse if fixed (the schema you want is useful only when you need to have more than one class like DerivedSomething, but if you try to write more classes you will see that MustStop implementation is not reused); so, the code fixing all together will look like this:
 
// interfaces:

    public interface IAgnostic {
        bool MustStop { get; }
    } //interface IAgnostic

    public interface ISomething<T> : IAgnostic {
        void DoSomething(T item);
    } //ISomething<T>

//implementations:
 
    abstract class Agnostic : IAgnostic {
        bool IAgnostic.MustStop {
            get { return true; }
        } //MustStop
    } //class Agnostic

    class DerivedSomething : Agnostic, IAgnostic, ISomething<int> {
        void ISomething<int>.DoSomething(int item) {
            // Do stuff here, <T> is important for item.
        } //DoSomething
        //implementation of MustStop is reused
    } //class DerivedSomething
    class DerivedSomethingElse : Agnostic, IAgnostic, ISomething<int> {
        void ISomething<int>.DoSomething(int item) {
            // Do stuff here, <T> is important for item.
        } //DoSomethingElse
        //implementation of MustStop is again reused
    } //class DerivedSomething

// usage:

    class Test {
        void TestMethod() {
            DerivedSomething thing = new DerivedSomething();
            //an extra variable somethigReferenced helps to
            //avoid type case, which would be less safe:
            ISomething<int> somethigReferenced = thing; 
            if (somethigReferenced.MustStop)
                Console.WriteLine("Stop!");
            else
                Console.WriteLine("Don't stop!");
        } //TestMethod
    } //class Test
 
I fix to the lack of code reuse is done via additional interface IAgnostic that is, agnostic to generic parameters and additional abstract implementation class IAgnostic. The fix is demonstrated by having two different terminal completely implementing classes, DerivedSomething and DerivedSomethingElse.
 
Now it's really right.
 
[END EDIT #2]
 
Now, I gave you the resolution which does not even touch the root topic collectively named "covariance and contravariance". To really understand these issues you really need to learn this topic. In C# practice, it's mostly about new features introduced to C# v.4 in comparison with prior versions.
 
So, try to read and understand this:
http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29[^],
http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx[^] (you really need to read all parts of it, but it needs some effort to find them; the navigation in this blog really needs improvement!),
http://blogs.msdn.com/b/ericlippert/archive/2007/10/26/covariance-and-contravariance-in-c-part-five-interface-variance.aspx[^],
http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx[^].
 
Just to give you the idea how much C# and .NET are lost in covariance/contravariance issues:
//you can do this:
string[] strings = new string[] { "1", "2", };
object[] objectsobjects = strings;
 
//but you cannot do this, no matter with v.4 or prior version:
System.Collections.Generic.List<string> strList = new System.Collections.Generic.List<string>();
System.Collections.Generic.List<object> objList = strList; //with case or not
 
The covariance/contravariance issues come into play each time there is a class using instances of other classes when using and used types are derivable. So, the issues are about arrays, generic containers and generic delegates. This goes beyond the casting topics we're discussing here.
 
—SA
  Permalink  
v10
Comments
Espen Harlinn at 16-Oct-11 17:32pm
   
Excellent effort, Sergey - obviously this deserves a 10 on it's own, but as that's not possible you have my 5+ :)
SAKryukov at 16-Oct-11 17:38pm
   
Thank you very much, Espen.
(I just added a paragraph and then a fix.)
--SA
Naerling at 16-Oct-11 17:38pm
   
Well, that just really did it. Thanks for the links, I am going to read them all. As Espen said, that deserves a 10, but I can only vote 5. So here it is once again!
I have already removed half of the Interfaces from my code (all non-generic ones) since they were simply not necessary anymore after your explanation.
Thanks for your efforts, it is really appreciated! :)
SAKryukov at 16-Oct-11 17:43pm
   
You're very welcome, thank you for interesting question.
By the way, I just added one more funny paragraph, see [EDIT].
 
Good luck, call again.
--SA
SAKryukov at 16-Oct-11 20:46pm
   
Actually, its wasn't all. After some thinking, I paid attention to more problems which I've fixed in new update, see [EDIT #2]. Now you should have right picture.
--SA
Naerling at 17-Oct-11 13:39pm
   
But now, IAgnostic does nothing on its own. In my case the MustStop Property is always dependent on the result of DoSomething. So for IAgnostic to actually do anything it should also Implement a non-Generic DoSomething. And in fact, my software is just the other way around. There is an Interface that has DoSomething<T> and a derived Interface that adds the MustStop Property :)
Of course There could be an IDoSomething<T> and an IMustStop and then an IDoSomethingAndMustStop<T> which Inherits the former two.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Sergey Alexandrovich Kryukov 404
1 Nirav Prabtani 389
2 Abhinav S 210
3 PIEBALDconsult 160
4 Dave Kreskowiak 155
0 OriginalGriff 7,580
1 Sergey Alexandrovich Kryukov 6,806
2 Maciej Los 3,919
3 Peter Leow 3,693
4 CHill60 2,742


Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 16 Oct 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100