简体   繁体   English

动态和可选方法参数

[英]dynamic AND optional method parameters

So C# supports optional parameters: 因此,C#支持可选参数:

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

And dynamic method params: 和动态方法参数:

void MethodName(dynamic param) { }

But unfortunately, you cannot use them together (optional param values must be constants): 但不幸的是,您不能一起使用它们(可选的param值必须是常量):

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

I have used things like this in the past: 我过去曾经使用过这样的东西:

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);
}

but that's a lot of extra work and type-specific coding where a new class or just using a dynamic would be easier, as long as you KNOW what the dynamic type is supposed to be.. but dynamics don't give IntelliSense (and reasonably so). 但这需要大量额外的工作和特定于类型的编码,只要您知道动态类型应该是什么,就可以轻松地使用新类或仅使用动态类型。.但是动态不会提供IntelliSense(并且合理地所以)。

I would prefer to use an interface, but cannot because the source types (in this ex: ThisType, ThatType) have different property names, and I do not have control over them (3rd-party assembly). 我希望使用一个接口,但是不能,因为源类型(在此示例中:ThisType,ThatType)具有不同的属性名称,并且我无法控制它们(第三方程序集)。

They ARE, however, partial classes, so I could create an interface with the signature of the anonymous type with unified property names AND the different property names, implement the interface in a partial, create dummy properties for the missing values from the 'other' type, and then pull the values from the respective properties depending on the type.. 它们是部分类,因此我可以创建具有匿名类型的签名的接口,该匿名类型的签名具有统一的属性名称和不同的属性名称,以部分方式实现接口,为“其他”中的缺失值创建虚拟属性类型,然后根据类型从相应的属性中提取值。

..but that is also too much work .. especially if i'm going through all the effort to create 3 new items (interface, 2 partials). ..但那也是太多的工作..尤其是如果我正在努力创建3个新项目(界面,2个部分)。 It would be simpler to create the anon type as a real class and translate it from the 2 previous types. 将anon类型创建为真实类并从之前的2种类型中进行转换会更简单。

All that is to ask if there are any clever ways to accomplish what I'm wanting; 这就是问是否有任何聪明的方法来完成我想要的事情; optional dynamic parameters that allow intellisense to work? 允许智能感知工作的可选动态参数?

I know this is a goofy question .. and basically amounts to: how can I define a class without actually defining it .. just wondering if there are any wizards out there with tricks up their sleeves other than the Cast(T,Type) route :) 我知道这是一个愚蠢的问题..基本上等于:我该如何定义一个类而不实际定义它..我只是想知道是否存在除Cast(T,Type)路线以外的其他任何带有窍门的向导:)

The answer here is: don't do this. 答案是: 不要这样做。

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

Feel free to use lots of these small definitions; 随意使用许多这些小的定义; preferably with names that actually document what they represent. 最好使用实际记录其代表名称的名称。 You'll get compile time checking, intellisense, and your code will be more readable as this is a form of documentation. 您将获得编译时检查,智能感知,并且您的代码将更具可读性,因为这是一种文档形式。 You might also instead use a Tuple , though I find they make your code less readable, particularly if they need to go in a heavily nested generic argument specification. 您也可以改用Tuple ,尽管我发现它们使您的代码可读性降低,尤其是当它们需要使用大量嵌套的通用参数规范时。 Nevertheless, tuples are still better than a dynamics+anonymous type hack. 尽管如此,元组仍然比动态+匿名类型hack更好。

A good starting point would be... 一个好的起点是...

  • Never use dynamic : this is a feature of last resort. 永远不要使用dynamic :这是不得已的功能。
  • Never use optional arguments: this too is a feature of last resort. 切勿使用可选参数:这也是不得已的功能。

dynamic undermines the type systems and essentially means you get the bad parts of a statically typed language (wordy) without the good parts (fast, reliable, self-documenting, intellisense). dynamic破坏了类型系统,从本质上讲意味着您获得了静态类型语言的糟糕部分(罗y的)而没有良好的部分(快速,可靠,自我记录,智能感知)。 It's rarely worth it. 很少值得。

Optional arguments are bad because they break encapsulability, which is structured programming 101 since the 1970s - wrapping optional arguments implies repeating argument specifications and repeating default values. 可选参数很糟糕,因为它们破坏了可封装性,自1970年代以来,结构化编程就是101。包装可选参数意味着重复参数规范和重复默认值。 Additionally there is a minor technical limitation concerning the fact that they're resolved by the caller, not the callee, which won't bite you unless you deploy dll's in a fairly unusual fashion (this limitation matters for large libraries such as .NET itself). 此外,关于它们由调用者而不是被调用者解决的事实,存在一个较小的技术限制,除非您以相当不寻常的方式部署dll,否则它们不会咬您(此限制对于大型库(如.NET本身很重要) )。 Instead, consider (once again) small, one-use structs . 相反,(再一次)考虑小的一次性structs

I guess I would chuck the dynamic and optional part, does not seem like you really need it here. 我想我会喜欢动态的和可选的部分,似乎您并不是真的需要它。 Create a new type (class or struct, depending upon your needs): 创建一个新类型(类或结构,取决于您的需要):

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

    // you may want to add constructors
}

Then create some mapper methods (extension methods will do fine) 然后创建一些映射器方法(扩展方法会很好)

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 };
    }
}

Now whenever you call your method, 现在,无论何时调用方法,

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 });
}

just use the extension methods. 只需使用扩展方法。 The code gets much clearer this way I think. 我认为这种方式使代码更加清晰。

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

I wrote this without intellisense, sorry for typos. 我写这篇文章时没有智能感知,很抱歉打错了。

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

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