Как получить тип универсального аргумента из стекового фрейма?

Мы должны создавать экземпляры наших сущностей через фабрику, поскольку они по-разному настроены на клиенте и сервере. Я хочу убедиться, что это так, но не могу заставить его работать.

public interface IEntityFactory
{
    TEntity Create<TEntity>() where TEntity : new();
}

public abstract class Entity
{
    protected Entity()
    {
        VerifyEntityIsCreatedThroughFactory();
    }

    [Conditional("DEBUG")]
    private void VerifyEntityIsCreatedThroughFactory()
    {
        foreach (var methodBase in new StackTrace().GetFrames().Select(x => x.GetMethod()))
        {
            if (!typeof(IEntityFactory).IsAssignableFrom(methodBase.DeclaringType)
                || methodBase.Name != "Create")
                continue;

            // The generic type is TEnitiy but I want the provided type!
            if (methodBase.GetGenericArguments()[0] != GetType())
                Debug.Fail(string.Format("Use factory when creating {0}.", GetType().Name));
        }
    }
}

person Jonas Samuelsson    schedule 15.11.2008    source источник
comment
Интересный вопрос, но я не думаю, что это возможно.   -  person leppie    schedule 15.11.2008


Ответы (3)


Можно ли решить это структурно, а не во время выполнения? Можете ли вы разделить свои сущности и фабрику в другой сборке, а затем предоставить конструкторам сущностей internal область видимости, чтобы только фабрика могла их вызывать?

person tvanfosson    schedule 15.11.2008

Проблема в том, что тип фабричного метода разрешается во время выполнения, поэтому метод считается «открытым». В этом случае общий тип аргумента вернет TEntity, как вы видите.

К сожалению (если я что-то не упустил), единственный способ узнать, какой тип TEntity, - это если закрытый метод сначала создается с использованием MethodInfo.MakeGenericMethod, а затем выполняется, что, конечно, вряд ли будет сделано вашими вызывающими.

Дополнительные сведения см. на этой странице MSDN.

person DocMax    schedule 15.11.2008

Спасибо за ваши ответы. Установка конструктора на внутренний невозможна, поскольку у нас есть несколько сборок, содержащих сущности. Прямо сейчас я склоняюсь к созданию класса, в котором фабрика регистрирует тип для создания, а конструктор проверяет зарегистрированный тип, это не то решение, которое я бы предпочел, но пока оно подойдет.

person Jonas Samuelsson    schedule 15.11.2008