views:

1574

answers:

6

I am wondering what it would take to make something like this work:

using System;

class Program
{
    static void Main()
    {
     var f = new IFoo { 
                    Foo = "foo",
                    Print = () => Console.WriteLine(Foo)
            };
    }
}

interface IFoo
{
    String Foo { get; set; }
    void Print();
}

The anonymous type created would look something like this:

internal sealed class <>f__AnonymousType0<<Foo>j__TPar> : IFoo
{
    readonly <Foo>j__TPar <Foo>i__Field;

    public <>f__AnonymousType0(<Foo>j__TPar Foo)
    {
        this.<Foo>i__Field = Foo;
    }

    public <Foo>j__TPar Foo
    {
        get { return this.<Foo>i__Field; }
    }

    public void Print()
    {
        Console.WriteLine(this.Foo);
    }
}

Is there any reason that the compiler would be unable to do something like this? Even for non-void methods or methods that take parameters the compiler should be able to infer the types from the interface declaration.

Disclaimer: While I do realize that this is not currently possible and it would make more sense to simply create a concrete class in this instance I am more interested in the theoretical aspects of this.

A: 

This wouldn't be possible currently.

What would be the difference between this and simply making IFoo a concrete class instead? Seems like that might be the better option.

What it would take? A new compiler and tons of checks to ensure they didn't break the other features. Personally, I think it'd just be easier to require developers to just create a concrete version of their class.

David Morton
+2  A: 
Joel Coehoorn
huh? "It already does, but the compiler doesn't know it"1. No it doesn't.2. It implements Serialize/Deserialize, but not the three properties Binder, Context, SurrogateSelector.
siz
Eh: you could shoehorn it in pretty easy. It _should_ have been built so you could have a method that accepts IFormatter instance and pass BinaryFormatter, SoapFormatter, the existing XmlSerializer, or your own IFormatter implementation without complaint.
Joel Coehoorn
Do you know that Oxygene [has this](http://prismwiki.codegear.com/en/Provide_Mixin-like_functionality)? I've also described a feature I'd like to see [here](http://codecrafter.blogspot.com/2010/10/roles-in-c.html).
Jordão
+4  A: 

An anonymous type can't be made to do anything except to have read-only properties.

Quoting the C# Programming Guide (Anonymous Types):

"Anonymous types are class types that consist of one or more public read-only properties. No other kinds of class members such as methods or events are allowed. An anonymous type cannot be cast to any interface or type except for object."

CMS
Yes, but I am hoping to revise that definition :)
Andrew Hare
A: 

Interesting idea, I'd be a little concerned that even if it could be done it might get confusing. E.g. when defining a property with non-trivial setters and getters, or how to disambiguate Foo if the the declaring type also contained a property called Foo.

I wonder if this would be easier in a more dynamic language, or even with the dynamic type and DLR in C# 4.0?

Perhaps today in C# some of the intent could be achieved with lambdas:

void Main() {
    var foo = new Foo();
    foo.Bar = "bar";
    foo.Print = () => Console.WriteLine(foo.Bar);
    foo.Print();
}


class Foo : IFoo {
    public String Bar { get; set; }    
    public Action Print {get;set;}
}
it depends
+5  A: 

There would be a few issues with overloaded members, indexers, and explicit interface implementations.

However, you could probably define the syntax in a way that allows you to resolve those problems.

Interestingly, you can get pretty close to what you want with C# 3.0 by writing a library. Basically, you could do this:

Create<IFoo>
(
    new
    {
        Foo = "foo",
        Print = (Action)(() => Console.WriteLine(Foo))
    }
);

Which is pretty close to what you want. The primary differences are a call to "Create" instead of the "new" keyword and the fact that you need to specify a delegate type.

The declaration of "Create" would look like this:

T Create<T> (object o)
{
//...
}

It would then use Reflection.Emit to generate an interface implementation dynamically at runtime.

This syntax, however, does have problems with explicit interface implementations and overloaded members, that you couldn't resolve without changing the compiler.

An alternative would be to use a collection initializer rather than an anonymous type. That would look like this:

Create
{
    new Members<IFoo>
    {
        {"Print", ((IFoo @this)=>Console.WriteLine(Foo))},
        {"Foo", "foo"}
    }
}

That would enable you to:

  1. Handle explicit interface implementation by specifying something like "IEnumerable.Current" for the string parameter.
  2. Define Members.Add so that you don't need to specify the delegate type in the initializer.

You would need to do a few things to implement this:

  1. Writer a small parser for C# type names. This only requires ".", "[]", "<>",ID, and the primitive type names, so you could probably do that in a few hours
  2. Implement a cache so that you only generate a single class for each unique interface
  3. Implement the Reflection.Emit code gen. This would probably take about 2 days at the most.
Scott Wisniewski
This was very much in the spirit of the question - thanks!
Andrew Hare
A: 

You could have something like anonymous classes in Java:

using System; 

class Program { 
  static void Main() { 
    var f = new IFoo() {  
      public String Foo { get { return "foo"; } } 
      public void Print() { Console.WriteLine(Foo); }
    }; 
  } 
} 

interface IFoo { 
  String Foo { get; set; } 
  void Print(); 
} 
Jordão