开发者

Select new object as a parameter while preserving it's run-time-generated type

Consider the following:

// select a subset of the DataTable
var subset = DataTable.Where(...).Select(row => new
{
    Id = Convert.ToInt32(row["Id"]),
    Name = row["Name"].ToString(),
    Email = row["Email"].ToString()
});

// or create a new object
var 开发者_如何学JAVAsubset = new {
    Id = 1,
    Name = "something random",
    Email = "name@domain.tld"
};

Is there any way to use the subset variable as a parameter to a method, without it being cast as a plain Object? Can you somehow carry the auto-generated type of the variable?

I am trying to avoid having to create new classes every time I want to pass LINQ subsets to methods.

Random generic approaches are welcome.


No, passing anonymous types about isn't generally a good idea because you lose the type information*. You should create a concrete type and use that instead.

var subset = DataTable.Where(...).Select(row => new SomeType
{
    Id = Convert.ToInt32(row["Id"]),
    Name = row["Name"].ToString(),
    Email = row["Email"].ToString()
});

Alternatively you can use the Tuple type if you are using .NET 4. This is a simple way to create "disposable" types and still get some type-safety.


*Actually there is a workaround, but I regard it is an ugly hack and would advise that you don't do it.


If I need to do this, I use resharper's "Replace Anonymous Type With Named Class" refactoring option. Then you have an appropriate named type to expose over the API, and you haven't had to do any work. This also gives you options to create it immutable (like anonymous types) or mutable, nested vs top-level, etc.

BTW, I don't recommend struct here (from the question).

Another option is to pass the behaviour into the method - i.e. an Action<int,string,string> callback - then do something like:

foreach(item in query) callback(item);

However, I don't like this as it is not obvious that there is a likely error in:

DoSomething(args, (id, email, name) => Email(To: email, Subject: name));

(the error being that it should probably be (id, name, email), if you see what I mean)


You can use a generic method:

public static void Foo<T>(T item)
{
    // Do whatever
}

Then if you call

Foo(subset);

the compiler will infer T for you. Whether or not that actually helps you is another matter... it depends on what the method is meant to do. Obviously Foo can't refer to Id, Name, Email etc.

In general, if multiple methods should know about the same members, then you should use a named type. The usual case for passing them to generic methods is where the method really doesn't care about what type is involved, such as in LINQ.

I've made a feature request for C# 5 that we should be able to create types which have all the same features as anonymous types (immutability, equality, hash code generation, ToString dumping) but for simple named types. We'll see if it actually happens...


Anonymous Types don't provide much help outside of the context they where created.

If you need to pass an Anonymous Type to a method, either this method is very generic like (Example)

void PrintAllObjectProperties(object obj);

witch you would use reflection to do the work, or you are doing something wrong.


Here's what I came up with...


Extension method on Object:

public static class ObjectExtensions
{
    /// <summary>
    /// Cast Object to anonymous type.
    /// E.G.: new Object().ToAnonymousType(new { Property = new Type() });
    /// </summary>
    public static T ToAnonymousType<T>(this Object o, T t)
    {
        return (T)o;
    }
}

Usage:

public void HandleAnonymousTypeAsParameter(Object o)
{
    var anonymousType = o.ToAnonymousType(new
    {
        Id = new Int32(),
        Foo = new String(),
        Bar = new String()
    });


    // ... You can do this in even less characters:
    var anonymousType = o.ToAnonymousType(new { Id = 0, Foo = "", Bar = "" });
}


HandleAnonymousTypeAsParameter(new
{
    Id = 1,
    Foo = "foo",
    Bar = "bar"
});


Credits goes to John Skeet and Thomas P.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜