Как сохранить HashTable в usersettings?

Вот функция, которую я использую (немного отредактированный). Это позволяет входные и выходные параметры. У меня только есть uniqueidentifier и реализованные типы varchar, но любые другие типы легко добавить. При использовании параметризованных хранимых процедур (или просто параметризованный sql..., этот код легко адаптирован к тому), это сделает жизнь намного легче.

Для вызывания функции Вам нужно соединение с SQL-сервером (скажите $conn),

$res=exec-storedprocedure-storedProcName 'stp_myProc' - параметры {Param1 = "Привет"; Param2=50}-outparams {идентификатор = "uniqueidentifier"} $conn

получают вывод proc от возвращенного объекта

$res.data #dataset содержащий таблицы данных, возвращенные выборами

$res.outputparams. Идентификатор #output идентификатор параметра (uniqueidentifier)

функция:

function exec-storedprocedure($storedProcName,  
        [hashtable] $parameters=@{},
        [hashtable] $outparams=@{},
        $conn,[switch]$help){ 

        function put-outputparameters($cmd, $outparams){
            foreach($outp in $outparams.Keys){
                $cmd.Parameters.Add("@$outp", (get-paramtype $outparams[$outp])).Direction=[System.Data.ParameterDirection]::Output
            }
        }
        function get-outputparameters($cmd,$outparams){
            foreach($p in $cmd.Parameters){
                if ($p.Direction -eq [System.Data.ParameterDirection]::Output){
                $outparams[$p.ParameterName.Replace("@","")]=$p.Value
                }
            }
        }

        function get-paramtype($typename,[switch]$help){
            switch ($typename){
                'uniqueidentifier' {[System.Data.SqlDbType]::UniqueIdentifier}
                'int' {[System.Data.SqlDbType]::Int}
                'xml' {[System.Data.SqlDbType]::Xml}
                'nvarchar' {[System.Data.SqlDbType]::NVarchar}
                default {[System.Data.SqlDbType]::Varchar}
            }
        }
        if ($help){
            $msg = @"
    Execute a sql statement.  Parameters are allowed.  
    Input parameters should be a dictionary of parameter names and values.
    Output parameters should be a dictionary of parameter names and types.
    Return value will usually be a list of datarows. 

    Usage: exec-query sql [inputparameters] [outputparameters] [conn] [-help]
    "@
            Write-Host $msg
            return
        }
        $close=($conn.State -eq [System.Data.ConnectionState]'Closed')
        if ($close) {
           $conn.Open()
        }

        $cmd=new-object system.Data.SqlClient.SqlCommand($sql,$conn)
        $cmd.CommandType=[System.Data.CommandType]'StoredProcedure'
        $cmd.CommandText=$storedProcName
        foreach($p in $parameters.Keys){
            $cmd.Parameters.AddWithValue("@$p",[string]$parameters[$p]).Direction=
                  [System.Data.ParameterDirection]::Input
        }

        put-outputparameters $cmd $outparams
        $ds=New-Object system.Data.DataSet
        $da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
        [Void]$da.fill($ds)
        if ($close) {
           $conn.Close()
        }
        get-outputparameters $cmd $outparams

        return @{data=$ds;outputparams=$outparams}
    }
5
задан Houman 22 November 2009 в 12:42
поделиться

1 ответ

The Hashtable does not support serialization to XML nor I believe to a simple string. These are the two serialization options available when you use a Settings.settings file and the associated auto-generated class.

However if you create your settings class by yourself and also manage the App.Config section you can persist an Hastable by using Binary serialization.

See the following example. It's a console application with following files:

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup 
      name="userSettings" 
      type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section 
        name="ConsoleApplication1.MyCustomSettings" 
        type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
        allowExeDefinition="MachineToLocalUser" 
        requirePermission="false" />
    </sectionGroup>
  </configSections>
  <userSettings>
    <ConsoleApplication1.MyCustomSettings>
      <setting name="MyHashtable" serializeAs="Binary">
        <value></value>
      </setting>
      <setting name="MyBackColor" serializeAs="String">
        <value>Silver</value>
      </setting>
    </ConsoleApplication1.MyCustomSettings>
  </userSettings>
</configuration>

Custom Settings Class created manually:

public class MyCustomSettings : ApplicationSettingsBase
{
    private static MyCustomSettings defaultInstance = (
        (MyCustomSettings)
        (ApplicationSettingsBase.Synchronized(new MyCustomSettings())));

    public static MyCustomSettings Default
    {
        get { return defaultInstance; }
    }

    [UserScopedSettingAttribute()]
    [DebuggerNonUserCodeAttribute()]
    [DefaultSettingValueAttribute("Silver")]
    public Color MyBackColor
    {
        get { return ((Color)(this["MyBackColor"])); }
        set { this["MyBackColor"] = value; }
    }

    [UserScopedSettingAttribute()]
    [DebuggerNonUserCodeAttribute()]
    [SettingsSerializeAs(SettingsSerializeAs.Binary)]
    public Hashtable MyHashtable
    {
        get { return ((Hashtable)(this["MyHashtable"])); }
        set { this["MyHashtable"] = value; }
    }
}

Program.cs

class Program
{
    static void Main(string[] args)
    {
        // For the first time no Hastable will exist.
        // Create one with the default values
        if (MyCustomSettings.Default.MyHashtable == null)
        {
            Console.WriteLine("Initializing Hashtable...");

            MyCustomSettings.Default.MyHashtable = new Hashtable();

            MyCustomSettings.Default.MyHashtable.Add(1, "foo");
            MyCustomSettings.Default.MyHashtable.Add(2, "bar");

            MyCustomSettings.Default.Save();
        }

        foreach (DictionaryEntry entry in MyCustomSettings.Default.MyHashtable)
        {
            Console.WriteLine(entry.Key + ": " + entry.Value);
        }

        Console.ReadKey();
    }
}

Update: Если вам нужно удобочитаемое представление данных, то подход, который вы используете, кажется разумным. Тем не менее, вы также можете попробовать другой подход, который лучше инкапсулирует логику преобразования в строку (XML) и из строки (XML).

Этот подход позволяет использовать поддержку IDE для файла Settings.settings, устраняя необходимость создания файла класс пользовательских настроек или возня с App.config.

Вам просто нужно реализовать собственный класс, который будет хранить ваши данные, в моем примере я унаследую этот класс от StringDictionary, а также реализую TypeConverter , который система настроек будет использовать для сохранения данных в строковом формате.

[TypeConverter(typeof(StringDictionaryTypeConverter))]
public class MyStringDictionary : StringDictionary
{
}

public class StringDictionaryTypeConverter : TypeConverter
{
    public override bool CanConvertFrom(
        ITypeDescriptorContext context, 
        Type sourceType)
    {
        if (sourceType.Equals(typeof(string)))
        {
            return true;
        }

        return base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(
        ITypeDescriptorContext context, 
        Type destinationType)
    {
        if (destinationType.Equals(typeof(string)))
        {
            return true;
        }

        return base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(
        ITypeDescriptorContext context, 
        CultureInfo culture, 
        object value)
    {
        if (value is string)
        {
            MyStringDictionary sd = new MyStringDictionary();

            XDocument xs = XDocument.Load(new StringReader(value as string));

            foreach (var item in xs.Descendants("entry"))
            {
                sd.Add(item.Element("key").Value, item.Element("value").Value);
            }

            return sd;
        }

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(
        ITypeDescriptorContext context, 
        CultureInfo culture, 
        object value, 
        Type destinationType)
    {
        if (destinationType.Equals(typeof(string)))
        {
            MyStringDictionary sd = value as MyStringDictionary;

            StringBuilder sb = new StringBuilder();

            sb.Append("<entries>");
            foreach (DictionaryEntry item in sd)
            {
                sb.AppendFormat(
                    "<entry><key>{0}</key><value>{1}</value></entry>", 
                    item.Key, 
                    item.Value);
            }
            sb.Append("</entries>");

            return sb.ToString();
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }
}

Теперь вам просто нужно использовать класс MyStringDictionary в качестве типа данных ваших настроек.

12
ответ дан 13 December 2019 в 05:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: