开发者

How can I make a .NET object friendlier to PowerShell?

开发者 https://www.devze.com 2023-02-15 03:41 出处:网络
I have a.NET class that I want to use from both C# and PowerShell. Cut down to its bare bones, it’s something like this:

I have a.NET class that I want to use from both C# and PowerShell. Cut down to its bare bones, it’s something like this:

class Record
{
    Dictionary<string, string> _fields = new Dictionary<string, string>();
    public IDictionary<string, string> Fields { get { return _fields; } }
    //...other stuff...
}

So I get a Record from somewhere and I can do record.Fields["foo"] = "bar" to modify/add fields from either C# or PowerShell. Works great.

But I’d like to make it a little more PowerShell-friendly. I want to do record.foo = "bar" and have it call the appropriate getters and setters. (I’d like to do the same with C# at some point, probably using dynamic, but that’s a separate fun project). Seems like I need a wrapping proxy class.

I know about add-member but I am worried that it would be slow and use a lot of memory when dealing with tens of thousands of records. I also don’t know how to have it handle record.somenewvalue = "abc".

I’m guessing that I want t开发者_如何转开发o create my proxy class in C#, using the facilities in System.Management.Automation or Microsoft.PowerShell but don’t quite know where to start. Can anyone help point me in the right direction?


I figured out one way to do it. Just make Record itself a dictionary. Here's some sample code:

$source = @"
    using System.Collections.Generic;
    public class Record : Dictionary<string, object>
    {
    }
"@

add-type -typedefinition $source

$x = new-object record
$x.add('abc', '1') # add
$x['def'] = '2'    # indexer
$x.ghi = 3         # "member"

$x

It outputs:

Key     Value                                                       
---     -----                                                       
abc     1                                                           
def     2                                                           
ghi     3                                                           


Here is some code illustrating three suggestions:

public class Record: IEnumerable<KeyValuePair<string, string>>
{
    public Record() {}

    public Record (Hashtable ht)
    {
        foreach (var key in ht.Keys)
        {
            this[key.ToString()] = ht[key].ToString();
        }
    }

    Dictionary<string, string> _fields = new Dictionary<string, string>();
    public IDictionary<string, string> Fields { get { return _fields; } }
    public string this[string fieldName] {
        get {
            return _fields[fieldName];
        }
        set { _fields[fieldName] = value; }
    }
    //...other stuff...
    public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
    {
        return _fields.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
  1. Implement this indexers
  2. Implement IEnumerable> to improve how powershell prints out the output
  3. A constructor taking a single hashtable as a parameter allows you to use @{} notation on initial assignment.

Now here is some powershell illustrating the improved usage:

Add-Type -Path 'C:\Users\zippy\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ClassLibrary1\bin\Debug\ClassLibrary1.dll'

[ClassLibrary1.Record] $foo = New-Object ClassLibrary1.Record;
$foo["bar"]
$foo["bar"] = "value";
$foo["bar"]

[ClassLibrary1.Record] $foo2 = @{
    "bar"= "value";
    "something"= "to talk about";
}; 

$foo2;
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号