2015-06-24 4 views
0

Вот то, что я до сих пор:Как вернуть тип, неизвестный во время компиляции?

public static object For<T>() 
{ 
    var builderName = typeof(T).Name + "Builder"; 
    var type = Type.GetType(builderName); 
    var builder = Activator.CreateInstance(type); 
    return builder; 
} 

И это не ошибка или что-нибудь, но проблема в том, когда я называю его:

var builder = Builder.For<MyModel>(); 

, а затем попытаться вызвать его методы :

builder.WithAnything() 

Она ошибки, потому что тип возвращаемого значения метода является просто объектом, а не тип, который был построен в рамках метода.

Целью этого является своего рода есть завод, который производит «Строители» (которые следуют свободно шаблон строитель) - и пытается создать некоторый синтаксический сахар, так что я не должен делать это:

(new MyModelBuilder()) 
    .WithParameter(2) 
    .WithAnother(3) 
    .Build(); 

по крайней мере, я нравится внешний вид этого гораздо лучше (так что это еще не чтобы быть достигнутой цели):

Builder.For<MyModel>() 
    .WithParemeter(2) 
    .WithAnother(3) 
    .Build(); 

Может ли это быть сделано в C#?

+0

Может быть что-то с [ 'dynamic' ключевым словом] (https://msdn.microsoft.com/en-us/library/dd264736.aspx)? –

+2

Кажется, что соотношение цены и стоимости не подходит для этого. – flq

+0

Являются ли методы всех строителей одинаковыми методами? Так что все строители поддерживают. 'WithParameter()'/'WithAnother()' или существуют специальные методы для конкретных сборщиков, например 'WithParameterOfFooBuilder()'/'WithParameterOfBarBuilder()' – xanatos

ответ

0

Определить базовый класс или интерфейс для типов модифицирующих:

public interface IBuilder 
{ 
    // common methods and properties here 
} 

Сделать все ваши строители наследуют от этого интерфейса или базового класса.

Затем обновите ваш тип возвращаемого значения:

public static IBuilder For<T>() 
{ 

} 
+2

Вы также ошибались. T не является строителем, но модель – flq

+0

Я думаю, он имел в виду, что тип возврата должен реализовывать интерфейс iBuilder i.e. 'public static IBuilder For ();' – Demarsch

+0

@flq Хороший улов. тип возврата должен быть IBuilder, а не T –

2

Servy указал, что вы оставили комментарий на теперь уже удален ответ, где вы говорите, каждый строитель может иметь различные методы.

Я не думаю, что этот точный подход будет работать, поскольку все строители будут иметь разные методы?

Если это так, то есть отдельные типы строителя могут иметь методы, которые вы хотите получить доступ, не существует никакого значения для Builder.For метода абстракции.

Иными словами, если нет единственного типа, который может быть возвращен For, который может быть вам полезен, за исключением конкретного типа строителя, который вы пытаетесь построить, вы можете также добавить новый экземпляр строителя и покончить с этим.

Если, с другой стороны, вы заинтересованы в разоблачении единообразный API, где аргументы могут быть проанализированы с помощью динамически разрешенного строителя построить объект, или другими словами, хочу сделать что-то вроде этого:

MyModel mm = Builder.For<MyModel>() 
    .WithProperty(x => x.MyModelProp) 
    .HavingValue(10) 
    .Build(); 

MyOtherModel mom = Builder.For<MyOtherModel>() 
    .WithProperty(x => x.MyOtherModelProp) 
    .HavingValue("hello") 
    .Build(); 

читать дальше.


Я спекулировать немного здесь, но я предполагаю, что в TBuilder должен иметь такого рода отношения с Т:

interface IBuilder<T> 
{ 
    T Build(); 
} 

Допустим, у вас есть:

class Tower 
{ 
    string Tallness { get { return "So tall"; } } 
} 
class TowerBuilder : IBuilder<Tower> 
{ 
    Tower Build() { return new Tower(); } 
} 

Вы можете реализовать метод следующим образом:

static IBuilder<T> BuilderFor<T>() 
{ 
    var builderName = typeof(T).Name + "Builder"; 
    var type = Type.GetType(builderName); 
    var builder = (IBuilder<T>)Activator.CreateInstance(type); 
    return builder; 
} 

Затем сделайте:

var tb = BuilderFor<Tower>(); 
var towerTallness = tb.Build().Tallness; 
+0

Спасибо за информацию! Я думаю, что нужна дополнительная информация. Вот пример шаблона, который я реализовал: http://stefanoricciardi.com/2010/04/14/a-fluent-builder-in-c/ Итак, я думаю, чтобы использовать вашу технику, лямбда должен был бы указать как параметр, так и значение? (что означает, что все свойства должны быть общедоступными (прямо сейчас, мои являются частными)) – NullVoxPopuli

+0

Вы правильно относитесь к взаимосвязи строителя с T – NullVoxPopuli

+0

Я предполагаю, что, альтернативно, есть способ использовать lamba, чтобы все атрибуты может быть назначено сразу? Вид вроде ruby ​​на присвоении атрибутов rails http://www.davidverhasselt.com/set-attributes-in-activerecord/ Но есть ли еще ошибки времени компиляции, если необходимо выполнить рефакторинг? – NullVoxPopuli

Смежные вопросы