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

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

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)


arrow_upward
2
arrow_downward

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

person tvanfosson    schedule 15.11.2008

arrow_upward
0
arrow_downward

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

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

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

person DocMax    schedule 15.11.2008

arrow_upward
0
arrow_downward

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

person Jonas Samuelsson    schedule 15.11.2008