Skip to main content
gamedev.net
🔒 Locked

Moving a generic function into an interface

Started by NightCreature83 7 replies 1k views
Original Post
NightCreature83
NightCreature83
A have a derived class that is a generic type now I would like to promote certain get and set functions up to the base class. However these get and sets wouldn't know what type they would be returning so these would have to be generic. Now what I want is for the implementation that the generic derived type is giving to be the one that is used for the base class methods. I want to avoid having to cast my interface to the derived generic type, the reason behind this is that the T value can be instantiated with a, for example, model class another one however is instantiated with a UIModel which in turn is derived from Model.

The following code is an example of what I want this doesn't compile however, and I know to little about C# generics to fix it.

[source lang="csharp"]
public abstract class IAttributeHandle : Handle
{
public IAttributeHandle() : base()
{
}
public IAttributeHandle(String name) : base(name)
{
}
public abstract T Value();
public abstract void setValue(T value);
}

public abstract class AttributeTypeHandle : IAttributeHandle
{
public AttributeTypeHandle() : base()
{
m_type = typeof(T);
}
public AttributeTypeHandle(String name, T value) : base(name)
{
m_type = typeof(T);
m_value = value;
}
public override T Value()
{
return m_value;
}
public override void setValue(T value)
{
m_value = value;
}
protected T m_value;
}
[/source]

There are more derived types of this class with definitions like the following:

[source lang="csharp"]

class BoolHandle : AttributeTypeHandle

{

}

[/source]

PS: not sure whats gone wrong but the highlight tags won't work for me

TheUnbeliever
TheUnbeliever
Make it generic: IAttributeHandle
[TheUnbeliever]
NightCreature83
NightCreature83

Make it generic: IAttributeHandle

Thats what I want to avoid as I don't want to write code that goes:
IAttributeHandle stringHandle = ;

This requires me to know the Type of the handle I am getting which I don't know in some cases.

TheUnbeliever
TheUnbeliever
I don't think this is logically possible. You can have 'get' if you a covariant type parameter, 'set' if it's contravariant. You can't have both unless you know the underlying type. (Consider: you can convert an IAttributeHandle to a UIModel to an IAttributeHandle to a Model, allowing you to 'get' it, but you can't then use set because you can't assign a Model to a UIModel.)

If you can live with that restriction, then you can do something like this:

[source lang="csharp"]interface IGettable
{ T Value { get; } }

interface ISettable
{ T Value { set; } }

abstract class Handle : IGettable, ISettable
{ /* ... */ }

// ...

IGettable h = uiModel.getHandle();
ISettable h = model.getHandle();[/source]
[TheUnbeliever]
NightCreature83
NightCreature83

I don't think this is logically possible. You can have 'get' if you a covariant type parameter, 'set' if it's contravariant. You can't have both unless you know the underlying type. (Consider: you can convert an IAttributeHandle to a UIModel to an IAttributeHandle to a Model, allowing you to 'get' it, but you can't then use set because you can't assign a Model to a UIModel.)

If you can live with that restriction, then you can do something like this:

[source lang="csharp"]interface IGettable
{ T Value { get; } }

interface ISettable
{ T Value { set; } }

abstract class Handle : IGettable, ISettable
{ /* ... */ }

// ...

IGettable h = uiModel.getHandle();
ISettable h = model.getHandle();[/source]

You misunderstand the hierarchy here a little bit and maybe I didn't make it clear enough but the Model and UIModel aren't part of the IAttributeHandle hierarchy they are the instantiated T values. Model and UIModel define their own heirarchy. So the hierarchies are Model <- UIModel and Handle <- IAttributeHandle <- AttributeTypeHandle <- AttributeModelHandle (T is defined as a model for this).

What I would like to have is a get more then a set on the IAttribute that allows me to return the value it is storing without having to specify T or cast to AttributeTypeHandle. This might not be possible as you are mentioning and it might be that my hierarchy is broken in this case and there is a simpler solution to the problem.

As an aside these handles do more then just store a name (this is hashed), value pair they are also de/serialiseable and take care of the de/serialisation for type T.
TheUnbeliever
TheUnbeliever
You misunderstand the hierarchy here a little bit


Nope, the way you describe it is the way I understood it.

What I would like to have is a get more then a set on the IAttribute that allows me to return the value it is storing without having to specify T or cast to AttributeTypeHandle.[/quote]

What do you want to then do with that value? If you want to treat it as more than an Object, without casting, then you're going to have to return either the underlying type, or some less-derived type. The code I posted gives you that:

[source lang="csharp"]interface IGetter { T Value { get; } }
interface ISetter { T Value { set; } }

abstract class IAttributeHandle : Handle, IGetter, ISetter
{ /* as it is */ };

class Model
{
// ...
public IAttributeHandle Handle
{ get; }
}

class UIModel
{
// exact detail depends on how you create an IAttributeHandle
public new IAttributeHandle Handle
{ get; }
}

// ...

void DoSomethingWithModel(IGetter m)
{ /* something */ }

// ...

IAttributeHandle m = /* something */;
DoSomethingWithModel(m);[/source]

The only way to get away from this would be to use dynamic types.
[TheUnbeliever]
NightCreature83
NightCreature83

[quote name='NightCreature83' timestamp='1321521508' post='4884899']You misunderstand the hierarchy here a little bit


Nope, the way you describe it is the way I understood it.

What I would like to have is a get more then a set on the IAttribute that allows me to return the value it is storing without having to specify T or cast to AttributeTypeHandle.[/quote]

What do you want to then do with that value? If you want to treat it as more than an Object, without casting, then you're going to have to return either the underlying type, or some less-derived type. The code I posted gives you that:

[source lang="csharp"]interface IGetter { T Value { get; } }
interface ISetter { T Value { set; } }

abstract class IAttributeHandle : Handle, IGetter, ISetter
{ /* as it is */ };

class Model
{
// ...
public IAttributeHandle Handle
{ get; }
}

class UIModel
{
// exact detail depends on how you create an IAttributeHandle
public new IAttributeHandle Handle
{ get; }
}

// ...

void DoSomethingWithModel(IGetter m)
{ /* something */ }

// ...

IAttributeHandle m = /* something */;
DoSomethingWithModel(m);[/source]

The only way to get away from this would be to use dynamic types.
[/quote]

See the problem starts in code like this which is in the render component.

[source lang="csharp"]

IAttributeHandle model = entity.getAttribute(FNVHash.hashString("model"));

AttributeHandleModel modelHandle = (AttributeHandleModel)model;
Model modelValue = modelHandle.Value();

[/source]


At this side I don't know what model is stored in the handle all i know it is a Model or one of it's derived classes, I am only interested in the Model exposed functions however.

The problem however here is that it can't cast to that at runtime and as there is no getter in the IAtributeHandle there is no way I could get the Value which I know is a Model or a derived version of a model. Maybe my problem is just in the instantiations of the Handles in this case and I should just be storing AttributeModelHandles instead of AttributeUIModelHandle.
TheUnbeliever
TheUnbeliever
[source lang="csharp"]

IAttributeHandle model = entity.getAttribute(FNVHash.hashString("model"));

AttributeHandleModel modelHandle = (AttributeHandleModel)model;
Model modelValue = modelHandle.Value();

[/source]


I don't think I'm quite understanding why this can't be

[source lang="csharp"]IGetter model = entity.getAttribute(FNVHash.hashString("model"));
Model modelValue = model.Value();[/source]
?

In practice, you'd probably want a more diamond-shaped tree for the handles, with both IGetter and ISetter extending some other interface, but this would allow you to do everything you've described so far.
[TheUnbeliever]
NightCreature83
NightCreature83

[quote name='NightCreature83' timestamp='1321553384' post='4885039'][source lang="csharp"]

IAttributeHandle model = entity.getAttribute(FNVHash.hashString("model"));

AttributeHandleModel modelHandle = (AttributeHandleModel)model;
Model modelValue = modelHandle.Value();

[/source]


I don't think I'm quite understanding why this can't be

[source lang="csharp"]IGetter model = entity.getAttribute(FNVHash.hashString("model"));
Model modelValue = model.Value();[/source]
?

In practice, you'd probably want a more diamond-shaped tree for the handles, with both IGetter and ISetter extending some other interface, but this would allow you to do everything you've described so far.
[/quote]

But it wouldn't as what I want is a way to access my values without having to specify the type in the base class interface, the whole point is I wish to do this without making IAttributeHandle a generic class. It can have generic method functions but not a generic type as an overall whole. Maybe I am not understanding generics properly as I am seeing them as type safe templates and those allow me to write a simple access function that is templated. C++ is the language I know most about and maybe I should have mentioned that.

I fixed it differently seeing that generics can't really contain primitive types and have to be ref types, I can then cast everything to an Object and stick a fairly generic function in the base class. I don't really mind having to cast to the type I am expecting, which is what I do know in most cases and this works nicely arround the fact that a AtrributeUIModel handle is not a AttributeModelHandle.


Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.