Мы должны создавать экземпляры наших сущностей через фабрику, поскольку они по-разному настроены на клиенте и сервере. Я хочу убедиться, что это так, но не могу заставить его работать.
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));
}
}
}





Проблема в том, что тип фабричного метода разрешается во время выполнения, поэтому метод считается «открытым». В этом случае общий тип аргумента вернет TEntity, как вы видите.
К сожалению (если я чего-то не упускаю), единственный способ узнать, какой тип TEntity - это сначала создать закрытый метод с использованием MethodInfo.MakeGenericMethod, а затем выполнить его, что, конечно, вряд ли будет сделано вашими вызывающими абонентами.
См. Этот Страница MSDN для получения дополнительных сведений.
Можно ли решить эту проблему структурно, а не во время выполнения? Можете ли вы разделить свои сущности и фабрику в другой сборке, а затем дать конструкторам сущностей internal область видимости, чтобы только фабрика могла их вызывать?
Спасибо за ответы. Установка конструктора на внутренний невозможна, поскольку у нас есть несколько сборок, содержащих сущности. Прямо сейчас я склоняюсь к созданию класса, в котором фабрика регистрирует тип для создания, а конструктор проверяет его на соответствие зарегистрированному типу, это не то решение, которое я предпочел бы, но на данный момент оно подойдет.
Интересный вопрос, но я не думаю, что это возможно.