Вот мой подход к открытию изображения без блокировки файла ...
public static Image FromFile(string path)
{
var bytes = File.ReadAllBytes(path);
var ms = new MemoryStream(bytes);
var img = Image.FromStream(ms);
return img;
}
UPDATE: Я сделал несколько перфекционных тестов, чтобы узнать, какой метод был самым быстрым. Я сравнил его с ответом @net_progs «копировать из растрового изображения» (который, кажется, ближе всего подходит, хотя и имеет некоторые проблемы). Я загрузил изображение 10000 раз для каждого метода и вычислил среднее время на изображение. Вот результаты:
Loading from bytes: ~0.26 ms per image.
Copying from bitmap: ~0.50 ms per image.
Результаты, похоже, имеют смысл, поскольку вам нужно дважды создать изображение, используя копию из растрового метода.
Неявный , когда Вы определяете свой интерфейс через участника на Вашем классе. Явный , когда Вы определяете методы в своем классе в интерфейсе. Я знаю, что сбивающие с толку звуки, но вот - то, что я имею в виду: IList.CopyTo
был бы неявно реализован как:
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
и явно как:
void ICollection.CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
различие, являющееся, который неявно доступен через Ваш класс, который Вы создали, когда это снято как тот класс, а также когда его бросок как интерфейс. Явная реализация позволяет ему только быть доступным, когда брошено как сам интерфейс.
MyClass myClass = new MyClass(); // Declared as concrete class
myclass.CopyTo //invalid with explicit
((IList)myClass).CopyTo //valid with explicit.
я использую явный, прежде всего, для содержания реализации в чистоте, или когда мне нужны две реализации. Но независимо я редко использую его.
я уверен, что существует больше причин использовать его, используют его, что другие отправят.
Посмотрите следующее сообщение в этом потоке для превосходного обоснования позади каждого.
Неявное определение должно было бы просто добавить методы / свойства, и т.д. потребованные интерфейсом непосредственно к классу как открытые методы.
Явное определение вынуждает участников быть представленными только, когда Вы работаете с интерфейсом непосредственно, а не конкретной реализацией. Это предпочтено в большинстве случаев.
Если Вы реализуете явно, Вы только будете в состоянии сослаться на интерфейсных участников через ссылку, которая имеет тип интерфейса. Ссылка, которая является типом класса с реализацией, не представит тех интерфейсных участников.
, Если Ваш класс с реализацией не общедоступен, за исключением метода, используемого для создания класса (который мог быть фабрикой или МОК контейнер), и за исключением методов интерфейса (конечно), тогда я не вижу преимущества для явной реализации интерфейсов.
Иначе, явно реализация интерфейсов удостоверяется, что ссылки на Ваш конкретный класс с реализацией не используются, позволяя Вам изменить ту реализацию в более позднее время. "Удостоверяется", я предполагаю, "преимущество". Хорошо учтенная реализация может выполнить это без явной реализации.
недостаток, по-моему, то, что Вы бросите типы к/от интерфейсу в коде реализации, который действительно имеет доступ к непубличным участникам.
Как много вещей, преимуществом является недостаток (и наоборот). Явно реализующие интерфейсы гарантируют, что Ваш код реализации реального класса не представлен.
В дополнение к превосходным ответам уже, если, существуют некоторые случаи, где явная реализация ТРЕБУЕТСЯ для компилятора быть в состоянии выяснить то, что требуется. Смотрите на IEnumerable<T>
как главный пример, который будет, вероятно, подходить справедливо часто.
Вот пример:
public abstract class StringList : IEnumerable<string>
{
private string[] _list = new string[] {"foo", "bar", "baz"};
// ...
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
foreach (string s in _list)
{ yield return s; }
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
Здесь, IEnumerable<string>
реализации IEnumerable
, следовательно мы должны также. Но держитесь, и дженерик и нормальная версия обе функции реализации с той же сигнатурой метода (C# игнорирует тип возврата для этого). Это абсолютно законно и прекрасно. Как компилятор разрешает, чтобы использовать? Это вынуждает Вас только иметь, самое большее, одно неявное определение, тогда это может разрешить то, что это должно.
т.е.
StringList sl = new StringList();
// uses the implicit definition.
IEnumerator<string> enumerableString = sl.GetEnumerator();
// same as above, only a little more explicit.
IEnumerator<string> enumerableString2 = ((IEnumerable<string>)sl).GetEnumerator();
// returns the same as above, but via the explicit definition
IEnumerator enumerableStuff = ((IEnumerable)sl).GetEnumerator();
пз: маленький кусочек косвенности в явном определении для IEnumerable работает, потому что в функции компилятор знает, что фактическим типом переменной является StringList, и это - то, как это разрешает вызов функции. Изящный небольшой факт для реализации некоторых слоев абстракции некоторые интерфейсы ядра.NET, кажется, накопился.
В дополнение к другим причинам, уже указанным, это - ситуация, в которой класс реализует два различных интерфейса, которые имеют свойство/метод с тем же именем и подписью.
/// <summary>
/// This is a Book
/// </summary>
interface IBook
{
string Title { get; }
string ISBN { get; }
}
/// <summary>
/// This is a Person
/// </summary>
interface IPerson
{
string Title { get; }
string Forename { get; }
string Surname { get; }
}
/// <summary>
/// This is some freaky book-person.
/// </summary>
class Class1 : IBook, IPerson
{
/// <summary>
/// This method is shared by both Book and Person
/// </summary>
public string Title
{
get
{
string personTitle = "Mr";
string bookTitle = "The Hitchhikers Guide to the Galaxy";
// What do we do here?
return null;
}
}
#region IPerson Members
public string Forename
{
get { return "Lee"; }
}
public string Surname
{
get { return "Oades"; }
}
#endregion
#region IBook Members
public string ISBN
{
get { return "1-904048-46-3"; }
}
#endregion
}
Этот код компиляции и выполнения хорошо, но свойство Title совместно используется.
Очевидно, мы хотели бы значение Заголовка, возвращенного для зависимости от того, рассматривали ли мы Class1 как Книгу или Человека. Это - когда мы можем использовать явный интерфейс.
string IBook.Title
{
get
{
return "The Hitchhikers Guide to the Galaxy";
}
}
string IPerson.Title
{
get
{
return "Mr";
}
}
public string Title
{
get { return "Still shared"; }
}
Уведомление, что явные интерфейсные определения выведены для Общественности - и следовательно Вы не можете объявить, что они общедоступны (или иначе) явно.
Примечание также, что у Вас может все еще быть "общая" версия (как показано выше), но пока это возможно, существование такого свойства сомнительно. Возможно, это могло использоваться в качестве реализации по умолчанию Заголовка - так, чтобы существующий код не должен был быть изменен для кастинга Class1 к IBook или IPerson.
, Если Вы не определяете "общий" (неявный) Заголовок, потребители Class1 должны явно экземпляры броска Class1 к IBook или IPerson сначала - иначе, код не скомпилирует.
Предыдущие ответы объясняют, почему реализация интерфейса явно в C# может быть предпочтительна (по главным образом формальным причинам). Однако существует одна ситуация, где явная реализация обязательна : Чтобы постараться не пропускать инкапсуляцию, когда интерфейс не - public
, но класс с реализацией public
.
// Given:
internal interface I { void M(); }
// Then explicit implementation correctly observes encapsulation of I:
// Both ((I)CExplicit).M and CExplicit.M are accessible only internally.
public class CExplicit: I { void I.M() { } }
// However, implicit implementation breaks encapsulation of I, because
// ((I)CImplicit).M is only accessible internally, while CImplicit.M is accessible publicly.
public class CImplicit: I { public void M() { } }
вышеупомянутая утечка неизбежна, потому что, согласно спецификация C#, "У всех интерфейсных участников неявно есть открытый доступ". Как следствие неявные реализации должны также дать public
доступ, даже если сам интерфейс, например, internal
.
реализация интерфейса Implicit в C# является большим удобством. На практике многие программисты используют его все время/везде без дальнейшего соображения. Это приводит к грязным поверхностям типа в лучшем случае и пропустило инкапсуляцию в худшем случае. Другие языки, такие как F#, даже не позволяют его .
Я предпочитаю использовать явную реализацию интерфейса, когда хочу отговорить «программирование на реализацию» ( Принципы проектирования из шаблонов проектирования ).
Например, в веб-приложении на основе MVP :
public interface INavigator {
void Redirect(string url);
}
public sealed class StandardNavigator : INavigator {
void INavigator.Redirect(string url) {
Response.Redirect(url);
}
}
Теперь другой класс (например, презентатор ) с меньшей вероятностью будет зависеть от реализации StandardNavigator и более вероятно зависеть от интерфейса INavigator (поскольку реализация должна быть приведена к интерфейсу, чтобы использовать метод Redirect).
Другой причиной, по которой я мог бы пойти с явной реализацией интерфейса, было бы сохранение «чистоты» интерфейса класса «по умолчанию». Например, если бы я разрабатывал серверный элемент управления ASP.NET , мне могли бы понадобиться два интерфейса:
Ниже приводится простой пример. Это поле со списком, в котором перечислены клиенты. В этом примере разработчик веб-страницы не заинтересован в заполнении списка; вместо этого они просто хотят иметь возможность выбрать клиента по GUID или получить GUID выбранного клиента. Презентатор заполняет поле при загрузке первой страницы, и этот докладчик инкапсулируется элементом управления.
public sealed class CustomerComboBox : ComboBox, ICustomerComboBox {
private readonly CustomerComboBoxPresenter presenter;
public CustomerComboBox() {
presenter = new CustomerComboBoxPresenter(this);
}
protected override void OnLoad() {
if (!Page.IsPostBack) presenter.HandleFirstLoad();
}
// Primary interface used by web page developers
public Guid ClientId {
get { return new Guid(SelectedItem.Value); }
set { SelectedItem.Value = value.ToString(); }
}
// "Hidden" interface used by presenter
IEnumerable<CustomerDto> ICustomerComboBox.DataSource { set; }
}
Презентатор заполняет источник данных, и разработчику веб-страницы никогда не нужно знать о его существовании.
Я бы не рекомендовал всегда использовать явные реализации интерфейса. Это всего лишь два примера, в которых они могут быть полезны.