Skip to content

Instantly share code, notes, and snippets.

@aemloviji
Last active June 5, 2022 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aemloviji/d7233a32f8b53c5b740b6f261574d1f4 to your computer and use it in GitHub Desktop.
Save aemloviji/d7233a32f8b53c5b740b6f261574d1f4 to your computer and use it in GitHub Desktop.
Creating and Using Dynamic Objects in C#

Creating and Using Dynamic Objects in C#

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/walkthrough-creating-and-using-dynamic-objects

TextFile1.txt

List of customers and suppliers

Supplier: Lucerne Publishing (https://www.lucernepublishing.com/)
Customer: Preston, Chris
Customer: Hines, Patrick
Customer: Cameron, Maria
Supplier: Graphic Design Institute (https://www.graphicdesigninstitute.com/)
Supplier: Fabrikam, Inc. (https://www.fabrikam.com/)
Customer: Seubert, Roxanne
Supplier: Proseware, Inc. (http://www.proseware.com/)
Customer: Adolphi, Stephan
Customer: Koch, Paul

To create a sample application that uses the custom dynamic object

dynamic rFile = new ReadOnlyFile(@"..\..\..\TextFile1.txt");
foreach (string line in rFile.Customer)
{
    Console.WriteLine(line);
}
Console.WriteLine("----------------------------");
foreach (string line in rFile.Customer(StringSearchOption.Contains, true))
{
    Console.WriteLine(line);
}

Create a Custom Dynamic Object

 public enum StringSearchOption
{
    StartsWith,
    Contains,
    EndsWith
}

internal class ReadOnlyFile : DynamicObject
{
    // Store the path to the file and the initial line count value.
    private string p_filePath;

    // Public constructor. Verify that file exists and store the path in
    // the private variable.
    public ReadOnlyFile(string filePath)
    {
        if (!File.Exists(filePath))
        {
            throw new Exception("File path does not exist.");
        }

        p_filePath = filePath;
    }

    public List<string> GetPropertyValue
    (
        string propertyName,
        StringSearchOption StringSearchOption = StringSearchOption.StartsWith,
        bool trimSpaces = true
    )
    {
        StreamReader? sr = null;
        List<string> results = new();
        string line;
        string testLine;

        try
        {
            sr = new StreamReader(p_filePath);

            while (!sr.EndOfStream)
            {
                line = sr.ReadLine();

                // Perform a case-insensitive search by using the specified search options.
                testLine = line.ToUpper();
                if (trimSpaces) { testLine = testLine.Trim(); }

                switch (StringSearchOption)
                {
                    case StringSearchOption.StartsWith:
                        if (testLine.StartsWith(propertyName.ToUpper())) { results.Add(line); }
                        break;
                    case StringSearchOption.Contains:
                        if (testLine.Contains(propertyName.ToUpper())) { results.Add(line); }
                        break;
                    case StringSearchOption.EndsWith:
                        if (testLine.EndsWith(propertyName.ToUpper())) { results.Add(line); }
                        break;
                }
            }
        }
        catch
        {
            // Trap any exception that occurs in reading the file and return null.
            results = null;
        }
        finally
        {
            if (sr != null) { sr.Close(); }
        }

        return results;
    }

    // Implement the TryGetMember method of the DynamicObject class for dynamic member calls.
    public override bool TryGetMember(GetMemberBinder binder,
                                      out object result)
    {
        result = GetPropertyValue(binder.Name);
        return result == null ? false : true;
    }


    // Implement the TryInvokeMember method of the DynamicObject class for
    // dynamic member calls that have arguments.
    public override bool TryInvokeMember
    (
        InvokeMemberBinder binder,
        object[] args,
        out object result
    )
    {
        StringSearchOption StringSearchOption = StringSearchOption.StartsWith;
        bool trimSpaces = true;

        try
        {
            if (args.Length > 0) { StringSearchOption = (StringSearchOption)args[0]; }
        }
        catch
        {
            throw new ArgumentException("StringSearchOption argument must be a StringSearchOption enum value.");
        }

        try
        {
            if (args.Length > 1) { trimSpaces = (bool)args[1]; }
        }
        catch
        {
            throw new ArgumentException("trimSpaces argument must be a Boolean value.");
        }

        result = GetPropertyValue(binder.Name, StringSearchOption, trimSpaces);

        return result == null ? false : true;
    }
}
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment