Как я могу проверить ошибку этого фабричного метода Create <T>, который использует активатор с параметрами? - PullRequest
0 голосов
/ 10 февраля 2012

Я не уверен, смогу ли я / как проверить, что конструктор действительно существует перед вызовом активатора в этом коде (непроверенный, поэтому могут быть ошибки, но, надеюсь, намерение понятно)шаблонное ограничение, которое говорит «где T имеет конструктор с сигнатурой S».

public class EntityContainerFactory
{
    public EntityContainerFactory(string sqlServerName, string databaseName, string metaData)
        : this(sqlServerName, databaseName, metaData, "System.Data.EntityClient")
    {
    }

    public EntityContainerFactory(string sqlServerName, string databaseName, string metaData, string dataProviderName)
    {
        SqlServerName = sqlServerName;
        DatabaseName = databaseName;
        Metadata = metaData;
        DataProviderName = dataProviderName;
    }

    // --> IS THERE ANY WAY TO CHECK THAT T HAS 
    //     A CONSTRUCTOR THAT TAKES AN ENTITY CONNECTION?
    public T Create<T>()
    {
        return (T)Activator.CreateInstance(typeof(T), CreateEntityConnection());
    }

    EntityConnection CreateEntityConnection()
    {
        SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
        sqlBuilder.DataSource = SqlServerName;
        sqlBuilder.InitialCatalog = DatabaseName;
        sqlBuilder.IntegratedSecurity = true;

        EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
        entityBuilder.Provider = DataProviderName;
        entityBuilder.ProviderConnectionString = sqlBuilder.ToString();
        entityBuilder.Metadata = Metadata;

        return new EntityConnection(entityBuilder.ConnectionString);
    }

    public string DatabaseName { get; set; }

    public string SqlServerName { get; set; }

    public string DataProviderName { get; set; }

    private string metaData;
    public string Metadata
    {
        get
        {
            string result;
            if (!this.metaData.StartsWith("res://"))
            {
                result = string.Format(@"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl", this.metaData);
            }
            else
            {
                result = this.metaData;
            }
            return result;
        }
        set
        {
            this.metaData = value;
        }
    }
}

Ответы [ 3 ]

3 голосов
/ 10 февраля 2012

Рассматривали ли вы использование интерфейсов вместо заводов?Вы можете получить намного лучшие результаты, и вы не столкнетесь с такими проблемами.

В любом случае:

where T : new()

Работает только для конструкторов без параметров.Если у вас есть это ограничение, вы можете сделать следующее, не задумываясь:

T obj = new T();

Вам придется проверять вручную.

ConstructorInfo ctor = typeof(T).GetConstructor(new Type[] { EntityConnection });
if (ctor == null)
{
    // Handle an unwanted type.
}
else
{
    return (T)ctor.Invoke(entityConnection);
}
3 голосов
/ 10 февраля 2012

Нет, вы не можете - единственным доступным общим ограничением, связанным с конструктором, является new(), для которого требуется конструктор без параметров.

Один из вариантов - вместо этого требовать фабричный делегат:

public T Create<T>(Func<EntityConnection, T> factory)
{
    return factory(CreateEntityConnection());
}

Тогда вы можете использовать:

Create(connection => new Whatever(connection))

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

1 голос
/ 10 февраля 2012

Метод Type.GetConstructor (Type ())

Ищет открытый конструктор экземпляра, параметры которого соответствуют типы в указанном массиве.

...