34

Note: I know this is an awful idea in practice; I'm just curious about what the CLR allow you to do, with the goal of creating some sort of 'modify a class after creating it' preprocessor.

Suppose I have the following class, which was defined in another assembly so I can't change it.

class Person {
    public string Greet() => "Hello!";
}

I now define an interface, and a method, like the following:

interface IGreetable {
    string Greet();
} 

// ...

void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());

The class Person does not explicity implement IGreetable, but it could do without any modification to its methods.

With that, is there any way whatsoever, using Reflection, the DLR or anything else, in which an instance of Person could be passed successfully to PrintGreeting without modifying any of the code above?

Aaron Christiansen
  • 11,584
  • 5
  • 52
  • 78
  • I understand you can't modify the code, but just for personal knowledge, could you pass a generic to PrintGreeting and get the result you're looking for? Just curious... – Brandon Miller Jan 29 '18 at 18:49
  • 4
    You could always just write your own class "InterfacedPerson" that encapsulates a Person and implents IGreetable. Encapsulation is something you have to do regulary working with the MVVM Pattern, to turn dumb Model Classes into ViewModel clases wich have properties with ChangeNotificaiton. – Christopher Jan 29 '18 at 18:50
  • 8
    This isn't "terrible" (as that implies the idea is unsound in principal), it just isn't how C#/.NET works - this is called "Structural Typing" (as opposed to C#'s standard "Nominative Typing"), which ought to be a useful term to find C# [*dynamic magic / run-time*] support to "dynamically 'cast'/proxy a type to a type-equivalent interface" and/or alternatives that are more C#-preferred. – user2864740 Jan 29 '18 at 18:57
  • @BrandonMiller Probably not, because the compiler could never be certain that `T` would have a `Greet()` method. I believe a definition like `void PrintGreeting(T g) where T : IGreetable` would work, but that's not really any different from the code in the question. – Aaron Christiansen Jan 29 '18 at 18:57
  • @AaronChristiansen I see. Thank you for your clarification. – Brandon Miller Jan 29 '18 at 18:59
  • You could definitely use reflection to detect an interface, but unfortunately in your case, you'd have to use some sort of wrapper to pass the class instance into the method. – ryanwebjackson Jan 30 '18 at 03:38
  • If you *could* modify the code in question, you could pass the method itself in as Func. I guess you lose the name of the method, but you could name the parameter similarly. – ryanwebjackson Jan 30 '18 at 03:41
  • 3
    Instead of "structural typing", this appears to be closer to [Duck Typing](https://en.wikipedia.org/wiki/Duck_typing). Structural typing would be C++'s templates - checked at compile time without reflection, by the compiler. – MSalters Jan 30 '18 at 10:06
  • See my related Java question: https://stackoverflow.com/questions/5691449/why-interfaces-must-be-declared-in-java – leonbloy Jan 30 '18 at 14:43

7 Answers7

28

Try to use the library Impromptu-Interface

[The Impromptu-Interface] framework to allow you to wrap any object (static or dynamic) with a static interface even though it didn't inherit from it. It does this by emitting cached dynamic binding code inside a proxy.

This allows you to do something like this:

var person = new Person();
var greeter = person.ActLike<IGreetable>();
user2864740
  • 60,010
  • 15
  • 145
  • 220
Roy Sanchez
  • 835
  • 6
  • 12
  • 8
    Important point: Like similar approaches, a *new* object/instance is created to wrap/proxy the interface calls - this makes it a *proxy* and not a *'cast'* operation. Sometimes this is incompatible with other assumptions / code requirements. – user2864740 Jan 29 '18 at 19:10
  • 2
    This looks promising. Where does the `ActLike` method come from? Is it an extension method on `object` provided by the library? – Aaron Christiansen Jan 29 '18 at 19:17
  • @AaronChristiansen It does exactly that, in the Impromptu.cs class – Roy Sanchez Jan 29 '18 at 19:30
  • This appears to be the most elegant method of doing it. The only downside, though it doesn't seem this could be worked around, is that `g.GetType()` doesn't return `Person`. (Rather, it returns an `ActLike_IGreetable_...`.) Thanks for answering! – Aaron Christiansen Jan 30 '18 at 07:58
7

You could use a dynamic wrapper object to wire this up yourself, but you lose type safety inside the wrapping class:

class GreetableWrapper : IGreetable
{
    private dynamic _wrapped;
    public GreetableWrapper(dynamic wrapped)
    {
        _wrapped = wrapped;
    }

    public string Greet()
    {
        return _wrapped.Greet();
    }
}

static void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());
static void Main(string[] args)
{
    PrintGreeting(new GreetableWrapper(new Person()));
    Console.ReadLine();
}
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • Although this would work, I can't imagine it would scale very well due to requiring a new method implementation for every method inside the interface. Still, I suppose the methods could be generated via Reflection or something. Thanks for answering! – Aaron Christiansen Jan 29 '18 at 19:16
  • 2
    It's worth pointing out that you do not need dynamic here, since this is a wrapper class, anything could be in Greet(), and it would fulfill the interface as long as it returned a string. – ryanwebjackson Jan 30 '18 at 03:15
  • The reason for dynamic is if you have another class that does a `Greet()` you can just use the PersonWrapper class on that as well. Instead of tightly coupling it to `Person` – John Koerner Jan 30 '18 at 04:16
  • Shouldn't it then be a GreetableWrapper as it has nothing to do with a Person? – Vulcano Jan 30 '18 at 13:27
6

This may be quite easy soon. Type classes may be introduced to C# as shapes where you will be able to define features of a class and code against that shape and then make use of your code with any type that matches without the author of that code having to declare anything, pretty much as you describe.

The closest thing in C# right now is perhaps how foreach works with a type that has an GetEnumerator() returning an object of a type with a MoveNext() and Current even they don't implement IEnumerable etc. only while that is a built-in concept the compiler deals with, here you could define them.

Interestingly, it will also let you define static members.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
4

I don't believe this is possible. The compiler needs to see something that explicitly implements the interface or class so that the compiler can confirm everything is implemented.

If you could do it using redirection, you could fail to implement something. And that goes against the safety approach embraced by .NET.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 3
    This isn't possible with type-validation during compilation (no language/runtime-level Structural Typing), but it is possible to [dynamically] create proxy types. I believe this is understood, and may work for the OP as reflection is acknowledged. – user2864740 Jan 29 '18 at 19:06
  • @user2864740: Yes, I was responding in the context of the C# compiler. Seemed like that's what the OP was looking for but perhaps some of these more involved approaches is something that would work for him. – Jonathan Wood Jan 29 '18 at 20:22
4

An option is creating a wrapper class over the person and pass this wrapper to the method, the wrapper need to explicitly implement the interface.

Mauri
  • 257
  • 2
  • 6
  • I considered this, and it would likely work for most intents and purposes. However, if `PrintGreeting` called `g.GetType()`, I'd ideally like it to return `Person`; could this be done using the wrapper class? – Aaron Christiansen Jan 29 '18 at 18:55
  • 2
    @AaronChristiansen: Nope. `object.GetType` is not virtual; it always returns the true type of a thing. (With the exception of nullable value types, which are slightly weird. `GetType` on an `int?` will crash if the `int?` is null and return the `int` type if it is not, just as `GetType` on a `string` will crash if the string is null.) – Eric Lippert Jan 29 '18 at 19:06
  • @EricLippert That sounds like a bug that breaks the basic contract that `x.GetType()` should return the `System.Type` of `x`. – Nat Jan 30 '18 at 03:58
  • 2
    @Nat: But you've simply stated the contract wrong. The contract is that `x.GetType()` will throw `NullReferenceException` if `x` is `null`, and return the type of the object stored at `x` otherwise. The only trickery is that the CLR makes a nullable instance with `HasValue == false` *be* null for the purposes of this check. But if you see the Nullables as more of an interface than objects in their own right, it makes sense. – Ben Voigt Jan 30 '18 at 06:54
4

If you have control of the external code, and are willing to wrap the object (and it seems like all of the answers here wrap), dynamic binding and libraries like Impromptu-Interface seem to me like a lot of trouble for something that's essentially a one liner.

class GreetablePerson : Person, IGreetable { }

And you're done.

When the compiler is building up the GreetablePerson class, the method from Person ends up doing an implicit implementation of the interface, and everything "just works." The only irritation is that the code outside has to instantiate GreetablePerson objects, but in standard object oriented terminology, an instance of GreetablePerson is an instance of Person, so this seems to me like a valid answer to the question as asked.

If the requirements are changed such that you also have pre-existing instances of Person, then something like Impromptu-Interface may become more tempting, but even then you may want to consider giving GreetablePerson a constructor that copies from Person. Choosing the best path forward from there requires getting more details about the requirements and the actual implementation details of the Person class in question.

GrandOpener
  • 1,943
  • 1
  • 17
  • 25
1

In sort of an unrelated not, this is something that is commonly done in other languages, such as Scala and Haskell.

It's known as using what are called "type classes". Type classes essentially allow you to define behavior for a type as if it explicitly implemented an interface, without actually requiring it to do so. You can read more about it here.

wheeler
  • 2,823
  • 3
  • 27
  • 43