Brian Rogers

Hi Everyone,

Does anyone know how to determine if an instance is a descendant of an "open" generic class

e.g.

MyOpenClass<TData> : object

where TData : object

{

}

And

MyChildClass<TData> : MyOpenClass<TData>

where TData : object

{

}

And then I have an instand and want to know if it is a descendant:

myObject.GetType is MyOpenClass<TData> - This doesn't work unless TData is specified.

Any help is appreciated.

Thanks,

B.



Re: Visual C# Language Is descendant of "Open" generic class

Peter Ritchie

If you're outside of the MyChildClass or MyOpenClass, then yes, you'll have to supply a type for TData . For example

Code Snippet

if(myObject is MyOpenClass<FileStream>) {/* do something */}






Re: Visual C# Language Is descendant of "Open" generic class

Brian Rogers

Hi Peter,

I have this problem and have no idea how to handle it I think being able to test for a descendant of an open class is a pretty obvious function - don't you

Assuming I have something like this:

CustomError<TEnum> : Exception

and

BusinessError<TEnum> : CustomError<TEnum>

and

ControllerError<TEnum> : CustomError<TEnum>

Assume in my exception handler, I only want to act on CustomErrors, how do I handle that

e.g.

catch(Exception error)

{

if (error is CustomError<>)

// Do stuff

}

Thanks,

B.





Re: Visual C# Language Is descendant of "Open" generic class

Peter Ritchie

Brian Rogers wrote:

Hi Peter,

I have this problem and have no idea how to handle it I think being able to test for a descendant of an open class is a pretty obvious function - don't you

No, I don't. Without the type parameter the parametrized type cannot be instantiated which means it's not a real type yet so you don't have anything concrete to compare.

Brian Rogers wrote:

Assuming I have something like this:

CustomError<TEnum> : Exception

and

BusinessError<TEnum> : CustomError<TEnum>

and

ControllerError<TEnum> : CustomError<TEnum>

Assume in my exception handler, I only want to act on CustomErrors, how do I handle that

e.g.

catch(Exception error)

{

if (error is CustomError<>)

// Do stuff

}

I don't recommend creating exception hierarchies, especially deep ones. It's near impossible to keep the levels synchronized and there's nothing ensuring an implementer of an exception from a particular level will do it correctly or that something from any given level will be used appropriately. The .NET Framework is a good example, not even it is consistent with the way it deals the its exception hierarchy (for example, ApplicationException is thrown from a couple of places in the framework) Once the hierarchy is compromised like that the base exception classes become nothing but placeholders can can't be used for exception handling directly (i.e. you don't know what they mean when caught anymore).

I also don't recommend catching Exception. That catches all exceptions (including OutOfMemoryException, etc.). You should be doing something like this instead:

catch(CustomError<int> customErrorIntException)

{

// ...

}

Or, don't use generics...

You could use the GetType method on the object to get a Type object. You could then check the Name property to see if it is an instantiation of the generic in question; but you'll have to deal with Generics name decoration, for example CustomError<TEnum> would likely have a Name property with the value "CustomError'1". Something instantiated as BusinessError<SomeTypeName> would have a Type.Name property of "BusinessError'1", for example. That uses reflection and is really slow; so I don't recommend doing it. I would recommend redesigning so you don't require that sort of information.






Re: Visual C# Language Is descendant of "Open" generic class

Brian Rogers

Hi Peter,

Thank you for the feedback. I appreciate your design views, but don't necessarily agree with them.

I don't think the statement that an "Open" generic is not a "Real" type is realistic and am disappointed that Microsoft would curb its design of generics based on that premise.

I guess reflection is about that only way to accomplish the type testing, slow or not.

Thanks,

B.





Re: Visual C# Language Is descendant of "Open" generic class

Peter Ritchie

Brian Rogers wrote:

Hi Peter,

Thank you for the feedback. I appreciate your design views, but don't necessarily agree with them.

I don't think the statement that an "Open" generic is not a "Real" type is realistic and am disappointed that Microsoft would curb its design of generics based on that premise.

I guess reflection is about that only way to accomplish the type testing, slow or not.

I agree it's disappointing; but if you can't instantiate the class the compiler cannot create the necessary parameter for the isinst IL instruction--which requires an object--from the is statement. Since isinst has existed since .NET 1.0--pre-Generics--it cannot deal with anything that cannot be instantiated. This also means the is C# keyword must also always deal with instantiable objects (as it first appeared before Generics). A new operator or method would have to be defined in order to support what you are asking. You could log a suggestion at http://connect.microsoft.com/VisualStudio/ if you feel strongly about it.

Even if you could do what you ask, how could you possibly cast the Exception object to a particular instance of your parametrized class (which is your end goal). If you have to know that type to do that then you can just use that with the is statement.






Re: Visual C# Language Is descendant of "Open" generic class

Brian Rogers

Hi Peter,

I understand the CLR open type dilemma. I would believe the lack of functionality is more of necessity to get the release out and of history, than it is of incorrect design. I understand how generics are slightly hampered by the legacy of 1.0.

My objective is to create a series of exception objects that use an "Enum" and object parameters to create their resource messages. The idea is that the messages can be displayed in any language, even after persistance. The parameterization is an Enum, and is translated into a string used to look up the reference.

Depending on the exception location e.g. business layer, client, server, the allowable values for the Enum differ, but they all descend from the same generic base class. And example is where I have a server service implementation, capable of genarating errors, a business controller, a business object and a data repository, each capable of creating a different set of errors. There error types are all open generics, inheriting from the shared open generic. Each instance of the exception is a closed generic, specifying the enum value to use.

Ultimately, client code would process exceptions using a particular closed generic, or look for a type specified flavour. Before I get to the final implementation though, I want to examine an exception that is of a closed type based on the open generic Error type. Testing for that "open" type and doing things e.g. replacing it with something else, is almost impossible.

To address the issue, I am going to implement a static helper method to help (as quickly as possible), examine the inheritance stack to determine the generics origin.

Thank you for all your input.

B.





Re: Visual C# Language Is descendant of "Open" generic class

Thomas Danecker

I also thought sometimes, that I'm missing the feature you're talking about but I ALWAYS detected a design-problem. It's a simple question: If you don't know what you want to deal with, why do you try to

It is not a lack of functionality, it is a design problem of the code "missing" that feature.

Of course one missing feature is to be able to convert a Generic<Concrete> to a Generic<Abstract>. But you will never have to convert a Generic<Concrete> to just a Generic. Because if your code doesn't know the Concrete type to deal with, it can't deal with it by design.

It's the same as casting Abstract to Concrete if the instance is of the type Concrete. In a good design you will never have to cast an Abstract to a Concret but this is done quite often because of laziness (or to be compatible with older code not supporting generics or with code not designed that well).

Post some more details of your code and I can help you to build a more appropriate design (or contact me per e-mail: tom UNDERLINE danecker AT hotmail DOT com).






Re: Visual C# Language Is descendant of "Open" generic class

Peter Ritchie

Thomas Danecker wrote:

Of course one missing feature is to be able to convert a Generic<Concrete> to a Generic<Abstract>.

I don't believe that is a missing feature. Generics are not Covariant, so even though Concrete may derive from Abstract, Generic<Concrete> is not a derivation of Generic<Abstract> and cannot be cast to Generic<Abstract>.

There's some good writings on Generics and covariance:

http://www.fotia.co.uk/fotia/DN.01.CoVariantGenericList.aspx

http://msdn2.microsoft.com/en-gb/library/aa479859.aspx#fundamentals_topic12






Re: Visual C# Language Is descendant of "Open" generic class

Thomas Danecker

I know that generics are not covariant but isn't it a missing feature of the CIL/CLI

It would be a nice discussion about the pros and contras of covariant generics and the covarinace of method return values (as descibed in your referenced msdn article) though I can't think of any contras.






Re: Visual C# Language Is descendant of "Open" generic class

Peter Ritchie

Thomas Danecker wrote:

I know that generics are not covariant but isn't it a missing feature of the CIL/CLI

It would be a nice discussion about the pros and contras of covariant generics and the covarinace of method return values (as descibed in your referenced msdn article) though I can't think of any contras.

The http://www.fotia.co.uk/fotia/DN.01.CoVariantGenericList.aspx site describes at least one contra to making generics covariant.




Re: Visual C# Language Is descendant of "Open" generic class

Thomas Danecker

Thanks for your hint. It's right, covariance is only safe if the objects are unmutable.




Re: Visual C# Language Is descendant of "Open" generic class

Peter Ritchie

I did manage to find something that you might find useful:

Code Snippet

catch(Exception error)

{

if (error.GetType().GetGenericTypeDefinition() == typeof(CustomError<>))

{

// Do stuff

}

}






Re: Visual C# Language Is descendant of "Open" generic class

Brian Rogers

Hi Peter,

Thank you and everyone who took part in this discussion for all your input.

I ended up writing this static helper method to solve the problem:

Code Snippet

/// <summary>
/// Tests if object is instance of generic type
/// </summary>
/// <param name="objectType"></param>
/// <param name="baseType"></param>
/// <returns></returns>
public static bool IsDescendantOf(Type objectType, Type baseType)
{
if ((objectType == null) || (baseType == null))
throw new ArgumentNullException();

// If the base type is not an
// open generic, use normal type comparison.
if (!baseType.IsGenericTypeDefinition)
return objectType.IsInstanceOfType(baseType);

// Don't go past ""Object".
if (objectType == typeof(Object))
return false;

// Recurses types until a match is found.
if ((objectType.IsGenericType) &&
(objectType.FullName.StartsWith(baseType.FullName)))
return true;

// Check the child
return IsDescendantOf(objectType.BaseType, baseType);
}

Thanks,

B.