Как отмечено в комментариях, ваш код завершается ошибкой, потому что для контейнера внедрения зависимостей ваша фабрика является допустимым источником для экземпляра IFoo
. Таким образом, при запросе разрешения всех служб IFoo
фабрика будет также запрашивать его.
Если вы хотите, чтобы это работало, вам придется каким-то образом разделить типы. Например, вы можете создать интерфейс маркера IActualFoo
, который вы будете использовать вместо регистрации своих сервисов:
services.AddTransient<IActualFoo, Foo1>()
services.AddTransient<IActualFoo, Foo2>();
Внутри вашей IFoo
фабрики вы можете затем разрешить IActualFoo
и привести их к IFoo
. Конечно, это означает, что IActualFoo
будет наследоваться от IFoo
и что ваши Foo
службы действительно должны реализовать IActualFoo
.
Другой подход - перенести ответственность за выбор правильной реализации IFoo
на фабрику. Как отмечали другие, у вашего подхода есть недостаток, заключающийся в том, что он будет создавать экземпляры для каждой отдельной реализации IFoo
и только затем выбирать правильный экземпляр. Это очень расточительно.
Было бы лучше, если бы фабрика могла принять решение о выборе правильной IFoo
реализации. Обычно это выглядит так:
services.AddTransient<Foo1>();
services.AddTransient<Foo2>();
services.AddTransient<IFoo>(sp =>
{
if (someMagicCondition)
return sp.GetService<Foo1>();
else
return sp.GetService<Foo2>();
});
Таким образом, фабрика создаст правильный экземпляр в зависимости от некоторой логики условий. Хотя этот подход часто используется, он требует полной ответственности на заводе и ограниченного набора возможных IFoo
реализаций во время разработки. Так что это не сработает, если вы хотите динамически добавлять реализации позже.
То, что вы также можете сделать, это зарегистрировать набор IFoo
фабрик . Поэтому вместо того, чтобы реализация IFoo
решала, является ли она правильной реализацией, перенесите эту логику на фабрику для каждой IFoo
реализации:
services.AddSingleton<IFooFactory, Foo1Factory>();
services.AddSingleton<IFooFactory, Foo2Factory>();
services.AddSingleton<IFoo>(sp =>
{
var factories = sp.GetServices<IFooFactory>();
return factories.FirstOrDefault(f => f.CanFoo())?.CreateFoo();
});
public interface IFooFactory
{
bool CanFoo();
IFoo CreateFoo();
}
public Foo1Factory : IFooFactory
{
public bool CanFoo() => true;
public IFoo CreateFoo() => new Foo1();
}
public Foo2Factory : IFooFactory
{
public bool CanFoo() => false;
public IFoo CreateFoo() => new Foo2();
}
Конечно, вместо обновления Foo
Реализации внутри фабрики также можно передать поставщику услуг и разрешить их (если они зарегистрированы).
Хотя не самое изящное ни надежное решение, вот метод, который возьмет Font
из тока Graphics
возразите и получите FontMetrics
для обнаружения, где нарисовать текст, и при необходимости, переместитесь в новую строку:
public void drawString(Graphics g, String s, int x, int y, int width)
{
// FontMetrics gives us information about the width,
// height, etc. of the current Graphics object's Font.
FontMetrics fm = g.getFontMetrics();
int lineHeight = fm.getHeight();
int curX = x;
int curY = y;
String[] words = s.split(" ");
for (String word : words)
{
// Find out thw width of the word.
int wordWidth = fm.stringWidth(word + " ");
// If text exceeds the width, then move to next line.
if (curX + wordWidth >= x + width)
{
curY += lineHeight;
curX = x;
}
g.drawString(word, curX, curY);
// Move over to the right for next word.
curX += wordWidth;
}
}
Эта реализация разделит данный String
в массив String
при помощи split
метод с пробелом как единственный разделитель слов, таким образом, это, вероятно, не очень устойчиво. Это также предполагает, что слово сопровождается пробелом и действует соответственно при перемещении curX
положение.
Я не рекомендовал бы использовать эту реализацию на вашем месте, но вероятно функции, которые необходимы для создания другой реализации, все еще использовали бы методы, предоставленные FontMetrics
класс.
Для перехода на новую строку Вам могло бы быть интересно тем, Как произвести Строку на нескольких строках с помощью Графики. Никакое выравнивание здесь, не уверенный, если это легко (или невозможно!) для добавления...