0

I am trying to cast anonymous type with the same property to an interface, but it's coming up with an error:

Unable to cast object of type '<>f__AnonymousType104`1[System.Int32]' to type 'IHasFiles'.

 public interface IHasFiles
 {
    int FileMasterId { get; }
 }

 var entity = new { FileMasterId = fileMasterId }.CastOrDefault<IHasFiles>();
 // This is the line where I get the error
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
threesixnine
  • 1,733
  • 7
  • 30
  • 56
  • Not sure if this is the Problem, but you use the Property Setter here: FileMasterId = fileMasterId. In your Interface you just got a Getter. – Sebi Jan 09 '17 at 10:27
  • The problem is that the anonymous object *doesn't* implement that interface so you are not allowed to cast to it. c# doesn't do duck typing so your only option would be to create a new object from your anonymous object and make sure the new object is of a type that implements the interface. – Chris Jan 09 '17 at 10:29
  • @Sebi It doesn't seem to be, I've added setter to the interface and it's still coming up with the same error. – threesixnine Jan 09 '17 at 10:29
  • It should work with a concrete type which inherits from IHasFiles. – ganeshran Jan 09 '17 at 10:31
  • Not strictly an interface but `public static THasFiles Cast(this dynamic anonType) where THasFiles : IHasFiles, new() { THasFiles result = new THasFiles(); foreach(var prop in typeof(THasFiles).GetProperties().Where(property => anonType.GetType().GetProperty(property.Name) != null))) { prop.SetValue(result, anonType.GetType().GetProperty(property.Name).GetValue(anonType)); } return result }` – mrogal.ski Jan 09 '17 at 10:33

1 Answers1

7

That is because interface implementation is explicit, not dynamic.

You can't cast an object to an interface reference simply because it has the same members, the type of that object has to explicitly implement the interface as well.

Anonymous types aren't castable to anything, other than object, dynamic (an object in disguise) or its own type, which is also a bit tricky since you don't exactly know the type (but there are ... hacks for this).

So no, you can't do that.

What you're looking for is commonly known as "duck typing", aka "if it walks like a duck, and if it quacks like a duck, then for all intents and purposes, it is a duck". This is not supported with stock C# or .NET but can be "mimicked" using code.

If you require an object that implements a specific interface you must declare a normal named type that implements the interface, there is no (good) way around it.


Now, this post is only, up until here, referring to the bit that the C# compiler and/or .NET will allow you to do. There is another concept in play here as well that, even if the C# compiler allowed you to do this, would make the concept shady.

And that is intent.

An interface does the following:

  • Declare a contract about what implementors has to supply of members
  • Declare a contract about what users can expect of members to be available
  • Declare a contract about the meaning of those members

This last part is hard to impose onto a type even if you could thread an interface over its head. If I write a class that just happens to have the same members that one of your interfaces, if you were to thread that interface onto my class, could you impose the same meaning of those members?

No, you can't.


Now, obviously, there are ways around it but none that are easy and I would say that in most cases they would be hacks that hide poor design.

In any case, to circumvent this you could, via reflection, build up another type that simultaneously wraps and delegates all members to the type of your object, as well as implement this interface, at runtime.

Is it good design? No, definitely not.

If you really want to go down this route you can, as commented below, use the "ImpromptuInterface" nuget package, and your code would then look like this:

var entity = new { FileMasterId = fileMasterId }.ActLike<IHasFiles>();

But I would strongly advice against this. Declare the type!

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825