SQL Server 2005, 2008, 2012, 2014 или 2016:
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'
Для показа только таблиц от конкретной базы данных
SELECT TABLE_NAME
FROM <DATABASE_NAME>.INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
Или,
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_CATALOG='dbName' --(for MySql, use: TABLE_SCHEMA='dbName' )
пз: Для SQL Server 2000:
SELECT * FROM sysobjects WHERE xtype='U'
Другое название этого автоматического кэширования результатов функции - мемоизация. Для открытого интерфейса рассмотрите что-нибудь в этом роде:
public Func<T,TResult> Memoize<T,TResult>(Func<T,TResult> f)
... и просто используйте полиморфизм для хранения T в словаре объекта.
Расширение диапазона делегатов можно реализовать с помощью каррирования и частичного применения функций. Примерно так:
static Func<T1,Func<T2,TResult>> Curry(Func<T1,T2,TResult> f)
{
return x => y => f(x, y);
}
// more versions of Curry
Поскольку Карри
превращает функции с несколькими аргументами в функции с одним аргументом (но которые могут возвращать функции), возвращаемые значения могут быть запомнены сами.
Другой способ сделать это. было бы использовать отражение для проверки типа делегата и хранить кортежи в словаре, а не просто тип аргумента. Упрощенный кортеж будет просто оберткой массива, в которой хэш-код и логика равенства используют глубокие сравнения и хеширование.
Сделать недействительность можно с помощью слабых ссылок, но создание словарей с ключами WeakReference
сложно - лучше всего это делать с поддержкой среды выполнения (значения WeakReference намного проще). Я считаю, что существуют некоторые реализации.
Безопасность потоков легко достигается за счет блокировки внутреннего словаря для событий мутации, но наличие словаря без блокировки может повысить производительность в сильно параллельных сценариях. Этот словарь, вероятно, будет еще труднее создать - хотя есть интересная презентация для Java здесь .
Я считаю, что существуют некоторые реализации.Безопасность потоков легко достигается за счет блокировки внутреннего словаря для событий мутации, но наличие словаря без блокировки может повысить производительность в сильно параллельных сценариях. Этот словарь, вероятно, будет еще труднее создать - хотя есть интересная презентация для Java здесь .
Я считаю, что существуют некоторые реализации.Безопасность потоков легко достигается за счет блокировки внутреннего словаря для событий мутации, но наличие словаря без блокировки может повысить производительность в сильно параллельных сценариях. Этот словарь, вероятно, будет еще труднее создать - хотя есть интересная презентация для Java здесь .
Вау - какая интуиция - я недавно задал вопрос о непрозрачных ключах в C # ... и потому что я Пытаюсь реализовать что-то связанное с кешированием результатов функций. Как весело.
Этот тип метапрограммирования может быть сложным с C # ... особенно потому, что параметры универсального типа могут привести к неудобному дублированию кода. Вам часто приходится повторять почти один и тот же код в нескольких местах с разными параметрами типа для достижения безопасности типов.
Итак, вот мой вариант вашего подхода, который использует мой непрозрачный ключевой шаблон и замыкания для создания кэшируемых функций. В приведенном ниже примере демонстрируется шаблон с одним или двумя аргументами, но его относительно легко расширить. Он также использует методы расширения для создания прозрачного шаблона для обертывания Func <> с кэшируемым Func <> с помощью метода AsCacheable ()
. Замыкания захватывают кеш, связанный с функцией, и делают его существование прозрачным для других вызывающих.
Этот метод имеет многие из тех же ограничений, что и ваш подход (безопасность потоков, привязка к ссылкам и т. Д.) - я подозреваю, что их несложно преодолеть - но он ДЕЙСТВИТЕЛЬНО поддерживает простой способ расширения до нескольких параметров, и это позволяет кешируемым функциям быть полностью заменяемыми обычными - поскольку они являются просто делегатом оболочки.
Также стоит отметить, что если вы создаете второй экземпляр CacheableFunction - вы получаете отдельный кеш. Это может быть как сильной стороной, так и недостатком ... поскольку в некоторых ситуациях вы можете не осознавать, что это происходит.
Вот код:
public interface IFunctionCache
{
void InvalidateAll();
// we could add more overloads here...
}
public static class Function
{
public class OpaqueKey<A, B>
{
private readonly object m_Key;
public A First { get; private set; }
public B Second { get; private set; }
public OpaqueKey(A k1, B k2)
{
m_Key = new { K1 = k1, K2 = k2 };
First = k1;
Second = k2;
}
public override bool Equals(object obj)
{
var otherKey = obj as OpaqueKey<A, B>;
return otherKey == null ? false : m_Key.Equals(otherKey.m_Key);
}
public override int GetHashCode()
{
return m_Key.GetHashCode();
}
}
private class AutoCache<TArgs,TR> : IFunctionCache
{
private readonly Dictionary<TArgs,TR> m_CachedResults
= new Dictionary<TArgs, TR>();
public bool IsCached( TArgs arg1 )
{
return m_CachedResults.ContainsKey( arg1 );
}
public TR AddCachedValue( TArgs arg1, TR value )
{
m_CachedResults.Add( arg1, value );
return value;
}
public TR GetCachedValue( TArgs arg1 )
{
return m_CachedResults[arg1];
}
public void InvalidateAll()
{
m_CachedResults.Clear();
}
}
public static Func<A,TR> AsCacheable<A,TR>( this Func<A,TR> function )
{
IFunctionCache ignored;
return AsCacheable( function, out ignored );
}
public static Func<A, TR> AsCacheable<A, TR>( this Func<A, TR> function, out IFunctionCache cache)
{
var autocache = new AutoCache<A,TR>();
cache = autocache;
return (a => autocache.IsCached(a) ?
autocache.GetCachedValue(a) :
autocache.AddCachedValue(a, function(a)));
}
public static Func<A,B,TR> AsCacheable<A,B,TR>( this Func<A,B,TR> function )
{
IFunctionCache ignored;
return AsCacheable(function, out ignored);
}
public static Func<A,B,TR> AsCacheable<A,B,TR>( this Func<A,B,TR> function, out IFunctionCache cache )
{
var autocache = new AutoCache<OpaqueKey<A, B>, TR>();
cache = autocache;
return ( a, b ) =>
{
var key = new OpaqueKey<A, B>( a, b );
return autocache.IsCached(key)
? autocache.GetCachedValue(key)
: autocache.AddCachedValue(key, function(a, b));
};
}
}
public class CacheableFunctionTests
{
public static void Main( string[] args )
{
Func<string, string> Reversal = s => new string( s.Reverse().ToArray() );
var CacheableReverse = Reversal.AsCacheable();
var reverse1 = CacheableReverse("Hello");
var reverse2 = CacheableReverse("Hello"); // step through to prove it uses caching
Func<int, int, double> Average = (a,b) => (a + b)/2.0;
var CacheableAverage = Average.AsCacheable();
var average1 = CacheableAverage(2, 4);
var average2 = CacheableAverage(2, 4);
}
}
Поскольку это в основном для образовательных целей - вам следует взглянуть на класс WeakReference, который позволяет сборщику мусора удалять неиспользуемые дескрипторы из вашего класса в многопоточной среде. Это довольно распространенный шаблон кеширования в .NET
Тем не менее - Caveat Emptor! Каждый кеш отличается. Создавая комплексное решение, вы часто попадаете в патологический случай, когда ваш «кеш» представляет собой просто прославленный словарь с множеством сложных вспомогательных методов, которые затрудняют чтение вашего кода.