繁体   English   中英

动态和可选方法参数

[英]dynamic AND optional method parameters

因此,C#支持可选参数:

void MethodName(string param = "optional!") { }

和动态方法参数:

void MethodName(dynamic param) { }

但不幸的是,您不能一起使用它们(可选的param值必须是常量):

void MethodName(dynamic param = new { p1 = "", p2 = 0M }) { }

我过去曾经使用过这样的东西:

void GenericAnonHandler<T>(IEnumerable<T> param)
{
    foreach(T item in param)
    {
        var typedItem = Cast(item, new { p1 = "", p2 = 0M });
        var p2 = typedItem.p2; // Hark, IntelliSense!
    }
}    
static T Cast<T>(object obj, T type)
{
    return (T)obj;
}
void CallingMethod()
{
    var list1 = new List<ThisType>() { ... };
    var list2 = new List<ThatType>() { ... };

    var anon1 = list1
        .Select(x => 
            new { p1 = x.sPropName, p2 = x.dPropName });

    var anon2 = list2
        .Select(x => 
            new { p1 = x.sPropName2, p2 = x.dPropName2 });

     var both = anon1.Concat(anon2);

     GenericAnonHandler(both);
}

但这需要大量额外的工作和特定于类型的编码,只要您知道动态类型应该是什么,就可以轻松地使用新类或仅使用动态类型。.但是动态不会提供IntelliSense(并且合理地所以)。

我希望使用一个接口,但是不能,因为源类型(在此示例中:ThisType,ThatType)具有不同的属性名称,并且我无法控制它们(第三方程序集)。

它们是部分类,因此我可以创建具有匿名类型的签名的接口,该匿名类型的签名具有统一的属性名称和不同的属性名称,以部分方式实现接口,为“其他”中的缺失值创建虚拟属性类型,然后根据类型从相应的属性中提取值。

..但那也是太多的工作..尤其是如果我正在努力创建3个新项目(界面,2个部分)。 将anon类型创建为真实类并从之前的2种类型中进行转换会更简单。

这就是问是否有任何聪明的方法来完成我想要的事情; 允许智能感知工作的可选动态参数?

我知道这是一个愚蠢的问题..基本上等于:我该如何定义一个类而不实际定义它..我只是想知道是否存在除Cast(T,Type)路线以外的其他任何带有窍门的向导:)

答案是: 不要这样做。

一个简短的定义就足够了: struct StrDec { public string p1; public decimal p2; } struct StrDec { public string p1; public decimal p2; }

随意使用许多这些小的定义; 最好使用实际记录其代表名称的名称。 您将获得编译时检查,智能感知,并且您的代码将更具可读性,因为这是一种文档形式。 您也可以改用Tuple ,尽管我发现它们使您的代码可读性降低,尤其是当它们需要使用大量嵌套的通用参数规范时。 尽管如此,元组仍然比动态+匿名类型hack更好。

一个好的起点是...

  • 永远不要使用dynamic :这是不得已的功能。
  • 切勿使用可选参数:这也是不得已的功能。

dynamic破坏了类型系统,从本质上讲意味着您获得了静态类型语言的糟糕部分(罗y的)而没有良好的部分(快速,可靠,自我记录,智能感知)。 很少值得。

可选参数很糟糕,因为它们破坏了可封装性,自1970年代以来,结构化编程就是101。包装可选参数意味着重复参数规范和重复默认值。 此外,关于它们由调用者而不是被调用者解决的事实,存在一个较小的技术限制,除非您以相当不寻常的方式部署dll,否则它们不会咬您(此限制对于大型库(如.NET本身很重要) )。 相反,(再一次)考虑小的一次性structs

我想我会喜欢动态的和可选的部分,似乎您并不是真的需要它。 创建一个新类型(类或结构,取决于您的需要):

public class ThirdType
{
    public string P1 { get; set; }
    public decimal P2 { get; set ; }

    // you may want to add constructors
}

然后创建一些映射器方法(扩展方法会很好)

public static class MapperExtensions 
{
    public static ThirdType ToThirdType(this ThisType obj)
    {
        return new ThirdType() { P1 = obj.sPropName, P2 = obj.dPropName };
    }

    public static ThirdType ToThirdType(this ThatType obj)
    {
        return new ThirdType() { P1 = obj.sPropName2, P2 = obj.dPropName2 };
    }
}

现在,无论何时调用方法,

void MethodName(ThirdType param)
{
    // A.) do this...
    if (param == null)
        param = new ThirdType() { P1 = "", P2 = 0M };

}

// ... or B.) create an overload (preferable to me)
void MethodName()
{
   MethodName(new ThirdType() { P1 = "", P2 = 0M });
}

只需使用扩展方法。 我认为这种方式使代码更加清晰。

private void ExecuteForBoth(ThisType obj1, ThatType obj2) // dummy method, just for illustration
{
    MethodName(obj1.ToThirdType());
    MethodName(obj2.ToThirdType());
}

我写这篇文章时没有智能感知,很抱歉打错了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM