C# 是否可以为字典的匿名类型创建隐式强制转换?

C# 是否可以为字典的匿名类型创建隐式强制转换?,c#,syntax,anonymous-types,C#,Syntax,Anonymous Types,我写了这样一个方法: using AttrDict = System.Collections.Generic.Dictionary<string, object>; using IAttrDict = System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object>>; static string HtmlTag(string tagN

我写了这样一个方法:

using AttrDict = System.Collections.Generic.Dictionary<string, object>;
using IAttrDict = System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object>>;

static string HtmlTag(string tagName, string content = null, IAttrDict attrs = null)
{
    var sb = new StringBuilder("<");
    sb.Append(tagName);
    if(attrs != null)
        foreach (var attr in attrs)
            sb.AppendFormat(" {0}=\"{1}\"", attr.Key, attr.Value.ToString().EscapeQuotes());
    if (content != null) sb.AppendFormat(">{0}</{1}>", content, tagName);
    else sb.Append(" />");
    return sb.ToString();
}
还不错。但若我想让用户传递一个匿名类型来代替dict呢?像

HtmlTag("div", "hello world", new {@class="green"});
更好!我可以很容易地编写重载,但问题是我将有大约50个这样的函数,我不想让每一个都重载。我希望我能写一个含蓄的演员为我做这项工作

public class AttrDict : Dictionary<string, object>
{
    public static implicit operator AttrDict(object obj)
    {
        // conversion from anonymous type to AttrDict here
    }
}
公共类属性:字典
{
公共静态隐式运算符AttrDict(对象obj)
{
//此处从匿名类型转换为属性
}
}
但C#根本不允许:

不允许向基类或从基类进行用户定义的转换


那么我能做什么呢?

您可以创建一个扩展方法,使用反射来进行您想要的转换。这看起来像:

public static class AttrDictX
{
    public static AttrDict ToAttrDict(this object obj)
    {
        if (obj == null)
            throw new ArgumentNullException("obj");

        var ans = new AttrDict();

        foreach (var prop in obj.GetType().GetProperties())
        {
            if (prop.CanRead)
                ans.Add(prop.Name, prop.GetValue(obj, null));
        }

        return ans;
    }
}
然后,呼叫站点将:

  • 包含一个
    .ToAttrDict()
    调用
  • (或者)如果可以为
    HtmlTag
    方法提供重载,而该方法采用
    对象
    ,并在内部进行转换,则看起来没有变化

  • 第二个选项是特别令人满意的,如果你不喜欢扩展<代码>对象< /> >,有些人(不是我)认为不好的做法。

    < P>你不能直接做你想要的。与ASP.NET MVC帮助程序方法一样,您可能应该选择另一种方法<代码>属性应仅为
    对象
    类型。然后,在方法体中,可以根据其运行时类型将其作为匿名类型或字典处理

    我的解决方案
    静态字符串转义符(此字符串str)
    {
    返回str.Replace(“\”,“\ \”);
    }
    静态IAttrDict ToDictionary(此对象对象)
    {
    返回obj.GetType().GetProperties().Where(prop=>prop.CanRead).ToDictionary(prop=>prop.Name,prop=>prop.GetValue(obj,null));
    }
    静态字符串HtmlTag(字符串标记名,字符串内容=null,对象属性=null)
    {
    IAttrDict attrDict=attrs!=null?attrs是IAttrDict?(IAttrDict)attrs:attrs.ToDictionary():null;
    var sb=新的StringBuilder(“{0}”,内容,标记名);
    否则,某人追加(“/>”);
    使某人返回字符串();
    }
    
    Heh。。。我想所有的东西都会通过HtmlTag函数过滤掉,所以..是的,这应该行得通。愚蠢的我。使用反射查询在匿名服务器上设置了哪些成员和值object@Pauli:是的,我知道该怎么做,问题是如何接受任何一种类型(匿名,或dict)。啊。。。是的,为此你必须使用最小公分母(object),这已经提到:)@Pauli:yeah..我希望我可以直接键入cast,而不是接受泛型对象,这样就可以更清楚地知道接受什么数据类型。我没有按你的方式执行的唯一原因(LINQ)您已经将
    字典
    子类化以创建
    属性
    ;我还以为您希望输出是那种类型的。@Ani:我只是想对它进行子类化,以便添加一个隐式运算符——它不允许我在未定义的类型上添加运算符。
    public static class AttrDictX
    {
        public static AttrDict ToAttrDict(this object obj)
        {
            if (obj == null)
                throw new ArgumentNullException("obj");
    
            var ans = new AttrDict();
    
            foreach (var prop in obj.GetType().GetProperties())
            {
                if (prop.CanRead)
                    ans.Add(prop.Name, prop.GetValue(obj, null));
            }
    
            return ans;
        }
    }
    
    static string EscapeQuotes(this string str)
    {
        return str.Replace("\"", "\\\"");
    }
    
    static IAttrDict ToDictionary(this object obj)
    {
        return obj.GetType().GetProperties().Where(prop => prop.CanRead).ToDictionary(prop => prop.Name, prop => prop.GetValue(obj, null));
    }
    
    static string HtmlTag(string tagName, string content = null, object attrs = null)
    {
        IAttrDict attrDict = attrs != null ? attrs is IAttrDict ? (IAttrDict)attrs : attrs.ToDictionary() : null;
    
        var sb = new StringBuilder("<");
        sb.Append(tagName);
        if(attrDict != null)
            foreach (var attr in attrDict)
                sb.AppendFormat(" {0}=\"{1}\"", attr.Key, attr.Value.ToString().EscapeQuotes());
        if (content != null) sb.AppendFormat(">{0}</{1}>", content, tagName);
        else sb.Append(" />");
        return sb.ToString();
    }