views:

246

answers:

5

I am currently working with LINQ and C#.

I have a DropDownList of the tables in my LINQ to SQL model.

I want the user to be able to select a LINQ table name from the DropDown. In code I want to create an instance of that LINQ class and then run a Select or it or anything else I want.

How would I accomplish creating the object based on what object name in string the user chose? Am I thinking incorrectly from the start?

+5  A: 

You want Type.GetType(string) and Activator.CreateInstance(Type).

Note that Type.GetType(string) will only look in the currently executing assembly and mscorlib unless you specify the full type name including assembly. In either case, you need to specify the type name including namespace.

Another alternative is to use Assembly.GetType(string) to get the type directly from the string before calling Activator.CreateInstance.

(There are actually lots of alternatives here. If none of these help you, please post more info and I'm sure we can work out a way to go.)

Jon Skeet
+3  A: 

Since you tagged the post with ASP.NET, I am assuming that the list is on the client side. If that is the case, you should be very careful about trusting that data, and I would not recommend creating types directly from user input. You could use the data as input to a factory that could then return the proper instance (and handle any illegal input as you see fit).

Brian Rasmussen
+1  A: 

With LINQ-to-SQL, there are specific ways of doing this from the data-context; basically, db.GetTable. This returns an ITable, but it is a little tricky to work with an untyped ITable. You can enumerate it, at least...

To get the ITable, you normally need the Type, which you can get with (for example) Assembly.GetType:

    using (var ctx = new MyDataContext()) {
        string name = "Customer"; // type name
        Type ctxType = ctx.GetType();
        Type type = ctxType.Assembly.GetType(
            ctxType.Namespace + "." + name);
        ITable table = ctx.GetTable(type);
        foreach(var row in table) {
            Console.WriteLine(row); // works best if ToString overridden...
        }
    }

Of course, once you have the Type, you use use Activator to create new entity instances:

        object newObj = Activator.CreateInstance(type);
        // TODO: set properties (with reflection?)
        table.InsertOnSubmit(newObj);

but if you want to use the property-name, that can work too:

    using (var ctx = new MyDataContext()) {
        string name = "Customers"; // property name
        ITable table = (ITable) ctx.GetType()
            .GetProperty(name).GetValue(ctx, null);
        foreach (var row in table) {
            Console.WriteLine(row); // works best if ToString overridden...
        }
    }

Running filters (Where) etc is tricky with untyped data, as building the Expression would be tortuous. I'd probably start switching to a typed model at that point...

Marc Gravell
+1  A: 

Elaborating on Brian Rasmussen's warning: The types should be restricted and require conscious design. Preferable the "user-instantiable" types should be marked with a specific custom attribute that can be verified with reflection.

A: 

To follow on Marc Gravell's answer.

Doing as he suggested, I noticed a Cast<TResult> extension method (defined in System.Linq).

Unfortunately you can't seem to be able to do use the type instance to cast:

Type dcType = dc.GetType();
Type type = dcType.Assembly.GetType(String.Format("{0}.{1}", dcType.Namespace, name));
var row = dc.GetTable(type).Cast<type>().SingleOrDefault(i => i.ID == 123);
bounav
It seems that what I'm trying to do is asked here: http://stackoverflow.com/questions/791187/using-reflection-to-address-a-linqed-property
bounav