Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Suggestions needed: alternative to overloading "is" and "as" operators in .NET

I hope this question isn't deemed too subjective - I don't really expect a definitive answer, but I hope that everyone's opinion will at least help me form my own.

I'm implementing a custom type system, that is a superset of the classical OOP type system. In this type system, object instances may be combined at runtime to form new instances, while retaining individual identities.

This code:

var p = new Person();
var pa = new Partner(p);

...results in a single combined object, with "p" and "pa" being different OOP-conforming views on it. IOW, changing a property value on one of the views is immediately reflected on any other view that also contains this property.

This all works fine and well, but it's missing two key API's for querying type identities. I would really like to be able to write such code:

if (p is Partner)
{
    (p as Partner).SomePartnerProperty = "...";
}

This of course doesn't work, because the behaviour of "is" and "as" operators can't be overloaded/extended beyond what .NET's OOP rules dictate. Nontheless, I still need this feature in my type system.

My first thought was to use generic extension methods that would attach to all instances of my type system:

public static bool Is<T>(this BaseType target) where T : BaseType { ... }
public static T As<T>(this BaseType target) where T : BaseType { ... }

Ignoring the issue of name conflict in case-insensitive languages, this seems OK in terms of functionality:

if (p.Is<Partner>())
{
    p.As<Partner>().SomePartnerProperty = "...";
}

However, I can't help but wonder - is this really the nicest, most convenient API one can come up with?

How would you advise I implement these two operators so they feel natural to use in application code?

UPDATE: For anyone that is wondering about the purpose of such type system... Basically, each type falls into one of two categories: Identity or Role. In the example I gave above, Person is an Identity (by design), while Partner is a Role (again, by design - it could have been designed differently). The ground rule of this type system is that any number of Roles may be composed with any given Identity, while Identity itself may only be composed with a higher Identity (e.g. a Person may become a Contact, but can never become a Company). Such type system enables applications to transparently deal with e.g. Partner objects, regardless of what Identity they have (e.g. Person, Company, Bank, etc.).

like image 875
aoven Avatar asked Nov 15 '22 14:11

aoven


1 Answers

I'd suggest to use two simple functions.

The first one would (at least for me) be intuitive with a name like:

p.IsType(typeHere)
p.IsPartner()

and the second a simple To-Call:

p.ToPartner()

I wouldn't implement those as generics (just doesn't feel right for me), especially the last one not.

like image 70
Bobby Avatar answered Dec 20 '22 03:12

Bobby