0

Weird question here - something that's come up, due to the environment I'm working within.


A bit of a preface:

I am going to abuse well-known abstractions from the Taxonomic rank to describe the situation I'm stuck with - by design decisions which were not my own, and are now Live in production on high-use data processing systems. I'm working on using (consuming) an API that was designed by others at work, I have no input on, and just need to be able to write code against.

This API is actually automatically generated C# code that's been compiled, and defines a complex interfacing type system which describes 1 Top-level Interface, hundreds of Second-level interfaces, And hundreds of Third-level interfaces, with a relationship of 1:1 on the Second-level interfaces and Third-level interfaces - IE, for every second-level interface, there is exactly 1 third-level interface, which also implements the Second-level Interface, and the top-level interface explicitly.

I will describe my conundrum (roughly) using the first 3 ranks within the field of biology's Taxonomic rank system.


A Pattern I will be using here:

  1. I%Domain% Is kind of a generalized stub, indicating a collection of interfaces of some arbitrary Domain (IArchaea, IBacteria, IEukarya). It could be any of these three (and in reality, there are literally hundreds).
  2. I%Kingdom% Is kind of a generalized stub (similar to I%Domain%), which if I%Domain% is actually IEukarya, would contain patterns similar to IFungi, IProtista, IPlantae, IAnimalia. The metaphor here breaks down, as in reality, there is exactly 1 Interface of this third tier that directly correlates to the known interface of the second tier. However, for the purposes of promotion, this is actually unimportant - I'm merely pointing out the metaphor's inconsistency.
// Implemented, and "Cement". Our algorithm fundamentally works with
// IOrganism as the main type for everything, using reflection to
// iterate properties, due to the needs presented.
// Consider to be Tier-1 Interface.
interface IOrganism { /*...*/ }
// Implemented, and "Nebulous" (Could be IArchaea, IBacteria, IEukarya, etc...)
// Will never actually be IDomain, but will rather be one of
// IArchaea, IBacteria, IEukarya, in a more "generic" approach.
// Note: The %Domain% syntax is *is indicative of a
// "stub" for any arbitrary pre-defined Domain-like
// interfaces. See the pattern described above.
// Consider to be Tier-2 Interface, which is "inherited"
// from by exactly 1 Tier-3 Interface.
Interface I%Domain% : IOrganism { /*...*/ }
// Implemented, and "Nebulous". See above on the Pattern section,
// as well as the comment on I%Domain%.
// Note: The %Kingdom% is indicative of a "stub"
// for any arbitrary pre-defined Kingdom interfaces.
// Consider to be a Tier-3 Interface, for which exactly 1 exists which
// implements each Tier-2 Interface.
interface I%Kingdom% : I%Domain%, IOrganism { /*...*/ }

All work is being done upon the IOrganism interface, but it is known that every input interface to the described method (below) are also I%Kingdom% (which is also I%Domain%).

I need a Method in C# which can receive an input IOrganism, assume it is an I%Kingdom%, and promote it to the up-casted I%Domain% type, in a generalized fashion, returning it as an IOrganism. This is conceptually similar to unboxing, but with a 3-tier system, and defined via hierarchical patterns amongst Interfaces, without particular regard to underlying object-types, only interface declarations.

// Given an IOrganism which is provided as a sub-typed
// I%Kingdom%instance , returns the input object as a
// Type-cast I%Domain%, and stored as an IOrganism.
public static IOrganism PromoteType(IOrganism organismAs%Kingdom%)
{
    // Get the type of the base as the current base type.
    // Is approximately typeof(I%Kingdom%), but
    // Isn't actually a generic, and rather refers to
    // An arbitrary instance of an I%Kingdom%-type
    // of interface.
    Type baseType = organismAs%Kingdom%.GetType();

    // Throw exception if the type provided is not the expected type
    // Note: type-checking is an abstraction,
    // we need another logical statement to determine if it
    // is the I%Kingdom% "generalized" interface type
    // Assume the actual statement works.
    if (baseType != typeof(I%Kingdom%))
    {
        // assume a more descriptive error string here.
        string error = "Provided object was of an invalid type."
        throw new InvalidArgumentException(string.Format(error));
    }

    // Stores the type of I%Domain%, inherantly.
    // Use LinQ to retrieve the matching interited type.
    // Note: The Name.Equals()-logic on "IDomain" is an abstraction
    // of the real logic, we actually have another logical statement
    // to determine if it is really the I%Domain%-pattern in
    // a more "generalized" fashion. Assume the "real"
    // variant of this statement works properly.
    Type upcastTypeAsIDomain = baseType.GetInterfaces()
        .FirstOrDefault(
            currInterfaceType => currInterfaceType.Name.Equals("I%Domain%"));

    // Note: For the third time, I%Domain% here is a logical abstraction -
    // There is another statement I'm using which works,
    // I'm just representing the effective statement
    // Relative to the question's context.
    if (upcastTypeAsIDomain != typeof(I%Domain%))
    {
        // A more meaningfull error message exists in reality.
        string error = "Provided object didn't implement the proper I%Domain% interim type.";
        throw new InvalidArgumentException(string.Format(error));
    }

    return /*This is the line I need help on*/;
}

My question is on that return statement, how do I perform a "generic" (not to be confused with C# Generics) type-cast on the provided IOrganism, known to be an I%Kingdom% order of Interface, and return it as if it were an I%Domain%, conceptually similar to C#'s Unboxing, knowing the Type of the object cemently as IOrganism, but then casting it as the Type of the declared type, and storing it as if it's an IOrganism, but where the GetType() would return the corresponding I%Domain%, and not the true underlying I%Kingdom%? Reflection is fine to use here - I am aware of the performance cost, but that won't be an issue in the context this is running.

I envision some mythical syntax similar to:

// Obviously not a real Compileable line of C# - this is a pattern only.
IOrganism organismAsUpcastDomain = CAST_FROM_I%Kingdom%_TO_I%Domain%;

Is there any sort of "generic"-cast (not to be confused with C# generics) which convert from 1 Type (as an interface) to another type (also as an interface), pretending the underlying object's base type is now the second type, assuming the hierarchical definitions are correct? That way when I store this organismAs%Kingdom% within an IOrganism, the organismAs%Kingdom%.GetType() would return the type of I%Domain%, instead of I%Kingdom%, despite fundamentally still being an I%Kindom% internally?

The context in which this program runs will not be "live", in the sense that user-requests actively force the logic to execute, but rather, will be pre-run by developers, generate a cache-file which represents the results of this processing, and then can be looked up in real-time as per request, which will be hammered hundreds of thousands, to millions of times per day. It needs to be able to process the promotion of an arbitrary interface sub-type(depth 3) to 1 layer up (depth 2) (and stored within the tier 1 interface type).

It may not even be possible to do this in C#, as I'm unsure how well the underlying .NET Framework differentiates between the fundamental interface-type as if it is the underlying object's base type, and the type it's being stored as, allowing you to "pretend" the object of type C is really type B, stored within Type A, allowing you to invoke .GetType() on an instance of A, which would return a Type equal to typeof(B), while really being an object of Type C, effectively making it lie about its own heritage.

This may look similar to Covariance and Contravariance at first, but is different, due to the fact that I'm working with arbitary Interface Types that are behaviorally and hierarchically similar to I%Domain% and I%Kingdom%, while describing them utilizing reflection.


Thanks for even reading the post here, as it's

  1. Long
  2. Convoluted
  3. Abuses the term "generic" when not actually referring to true C# Generics
  4. Should be unnecessary, but due to the environment I'm programming within, (I'm writing a program that needs to use reflection on the declared types in a general fashion to perform work on all inputs regardless of types, following certain pre-known patterns and hierarchies, on a data structure that could literally change at any time, to perform generalized work on this abstraction).
  • a little bt hard to read if you use the type parameter syntax but actually just mean a placeholder inside the interface name – adjan Apr 13 '19 at 12:22
  • I agree. Do you have thoughts on a syntactical replacement? – Matthew K. Crandall Apr 13 '19 at 12:29
  • I think I could use something like I%Domain%, I%Kingdom%, etc..., and describe that notation as a convention in my premise. – Matthew K. Crandall Apr 13 '19 at 12:30
  • also, do i understand that correctly? Do you want to change the *type* of an instance? Like, having `GetType()` returning a different type than originally? – adjan Apr 13 '19 at 12:33
  • I don't want to change the underlying type, I want to make the object lie about the type and pretend it's actually the type of an up-casted variant. The system I'm working in is actually already doing this - I'm working with a concrete object, invoking .GetType() returns the type of I rather than the concrete type, and I'm looking to manipulate the object to force it to return I rather than I, for reflection purposes on the upcasted variant. That's a part of why this request seems so weird to me, and makes me question the viability of this approach in C#. – Matthew K. Crandall Apr 13 '19 at 12:36
  • I can get what I actually need accomplished if I modify the function I provided in my post to simply return the type it retrieved by the LinQ expression, and refactor a few hundred lines of code to use a provided type rather than rely upon an object's reported type by GetType(), but I was hoping there was some way coerce the .NET framework to make an object of most generic Interface Type A, which reports as Interface Type C, now report as Interface Type B, following reflection-based hierarchy. – Matthew K. Crandall Apr 13 '19 at 12:41
  • I changed the question to use I%Domain% and I%Kingdom% rather than I and I, to avoid the latent confusion with C# Generic syntax. – Matthew K. Crandall Apr 13 '19 at 12:57

1 Answers1

0

So I've refactored my code base allowing me to just return the reflected interface parent type (rather than attempt to perform some ungodly generic-cast), making the answer to this question a moot point for my needs, but I've also now come up with an answer that lets you provide an alias type for an object of any other type. At this point it's almost contrived, but if for some reason, if you're using reflection and want have an easy mechanism to track which degree within a complex inheritance chain your current object is being aliased as, you can use the following classes:

public abstract class TypeAlias
  {
    public virtual object ValueAsObject { get; set; }
    public virtual Type PresentingType { get; set; }
  }

  public class TypeAlias<T> : TypeAlias
    where T : class
  {
    private T underlyingTypeSafeObject;

    public TypeAlias()
      : base()
    {
      base.PresentingType = typeof(T);
    }

    public T TypeSafeObject
    {
      get
      {
        return this.underlyingTypeSafeObject;
      }

      set
      {
        this.underlyingTypeSafeObject = value;

        if (base.PresentingType == null && value != null)
        {
          base.PresentingType = value.GetType();
        }
      }
    }

    public override object ValueAsObject
    {
      get
      {
        return this.underlyingTypeSafeObject;
      }

      set
      {
        // returns null if cast conversion fails - not type-safe on the TypeAlias level.
        this.underlyingTypeSafeObject = value as T;
      }
    }

    public override Type PresentingType
    {
      get => base.PresentingType; set => base.PresentingType = value;
    }
}

With that convention, and with the following interfaces (and implementations) in mind:

  public interface IOrganism
  {
    string Be();
  }

  public interface IDomain : IOrganism
  {
    string DomainName { get; set; }
  }
  public interface IKingdom : IDomain, IOrganism
  {
    string KingdomName { get; set; }
  }

  public class SeventhDimension : IDomain
  {
    private string domainName = "7th Dimension";

    string IDomain.DomainName { get => domainName; set => domainName = value; }

    public virtual string Be()
    {
      return string.Format("{0} Exists.", this.domainName);
    }
  }

  public class KingdomHyrule : SeventhDimension, IKingdom, IDomain
  {
    private string kingdomName = "Hyrule";

    string IKingdom.KingdomName { get => kingdomName; set => kingdomName = value; }

    public virtual string Be()
    {
      string s = base.Be();
      s += string.Format(" Also, {0} Exists.", this.kingdomName);
      return s;
    }
  }

We can now have the following code to provide a different alias, which we can control the presentation of, to allow for reflection on differing degrees upon the inherited pedigree of any particular implementation of an object:

// Create a Hyrule Kingdom, which is also a SeventhDomain,
// and IOrganism, IKingdom, IDomain.
IOrganism testOrganism = new KingdomHyrule();
Console.WriteLine(testOrganism.Be());

// Construct a TypeAlias, which by default presents
// the type of the container you store it as,
// using Generics.
TypeAlias alias = new TypeAlias<SeventhDimension>()
{
  ValueAsObject = testOrganism
};

Console.WriteLine();

// Grab the real type of the testOrganism,
// which will be KingdomHyrule
Console.WriteLine(testOrganism.GetType().Name);

// Grab the faked type of testOrganism,
// which will be SeventhDimension, due to
// the construction of the Alias.
Console.WriteLine(alias.PresentingType.Name);

// Could be retrieved using reflection on Implementing Types
alias.PresentingType = typeof(IOrganism);
Console.WriteLine(alias.PresentingType.Name);

/* Output:
* 7th Dimension Exists. Also, Hyrule Exists. | from testOrganism.Be();
*
* KingdomHyrule | from testOrganism.GetType().Name;
* SeventhDimension | from alias.PresentingType.Name;
* IOrganism | from alias.PresentingType.Name, after assignment
* */

As I said above - I no longer even need this, but the classes TypeAlias and TypeAlias<T> make it easy to loosely couple an arbitrary instance of a class, and have it present any other type (which by convention could be used to allow you to use reflection to grab properties / methods out of reflectively detected base types).