哪个更好,Params还是List?

9

以下是我现有的代码,它是作为代理向客户端暴露的WCF服务方法:

public UnifiedDTO GetAllCardTitle(string trainSymbolOrCarLocation, 
                                  DateTime startDate, 
                                  DateTime endDate, 
                                  string procedureName = CardTitle.procedureNameTrainRuns)

该方法需要一个过程名称(作为最后一个参数),其余参数是绑定输入参数,然而问题在于,如果参数数量和类型发生更改,我们就没有灵活性。该项目处于初始阶段,所以肯定会进行更改。
我可以选择将该方法转换为以下形式:
public UnifiedDTO GetAllCardTitle(params object [] parameters)

我们有自由传递参数和过程细节并相应地进行绑定。但是,由于装箱和拆箱可能会出现性能问题。它需要客户端应用程序按正确的顺序和值传递参数以进行绑定,以便底层层期望。

public UnifiedDTO GetAllCardTitle(List<Filter> parameter, string procedureName)

Parameter类的定义如下:

public class Filter
{
    public string name { set; get; }
    public string value { set; get; }
    public string dataTypeID { set; get; }

    public Filter(string _name, string _value, string _dataTypeID)
    {
        name = _name;
        value = _value;
        dataTypeID = _dataTypeID;
    }
}

在这种给定过程的方法中,我们将每个参数与其名称值和DataType绑定,需要将该值强制转换为正确的数据类型,它比上一种方法更灵活,可以按任意顺序传递,因为绑定是按名称进行的。但是,这需要应用程序做更多的尽职调查。
在C#.Net中是否还有更好的方法来处理此情况?

3
дҪ иҖғиҷ‘иҝҮеҲӣе»әдёҖдёӘеҢ…еҗ«жүҖжңүзӯӣйҖүеҷЁеұһжҖ§зҡ„еҚ•дёӘCardQueryзұ»еҗ—пјҹ然еҗҺеҸӘйңҖдҪҝз”ЁGetAllCardTitle(CardQuery query)ж–№жі•еҚіеҸҜгҖӮ - Jon Skeet
7
附注:当涉及WCF服务时,装箱和拆箱的开销不是问题,因为服务操作调用通常具有更糟糕的开销 - 例如I/O(通过网络传输数据包)、网络延迟等。与此相比,装箱和拆箱可能非常快,因此您正在担心错误的事情。 - stakx - no longer contributing
很惊讶这个问题没有得到更多的赞 - 它是一个非常好的提问。 - aevitas
@MrinalKamboj:对于“StartDate”和“EndDate”?是的,我会将它们设置为“DateTime?”值。 - Jon Skeet
@Jon Skeet,这意味着它将包含所有可能的元素,只有必要的元素被分配,其余的都可以忽略。
  • 我们是否使用可空值类型来确保它们也是 Null,以便与引用类型相似?
  • 对于像 StartDate 这样的属性,它是 DateTime 类型,我们是否只有类似 Nullable<DateTime> valueStartDate 的东西,在内部映射到它并且如果为 null,则可以忽略它。这样我就不需要传递参数或为每个参数创建一个包含该参数名称和值的对象数组,用于内部绑定。
- Mrinal Kamboj
显示剩余4条评论
2个回答

1

无。 使用动态对象替代

要创建一个与DLR一起使用的C#类,最简单的方法是从DynamicObject派生。但是,在尝试在WCF服务中使用动态类型时会出现限制。尝试使用派生自DynamicObject的类型将导致在尝试使用WCF的DataContractSerializer进行序列化时出现运行时异常。

[DataContract]
public class SerializableDynamicObject : IDynamicMetaObjectProvider
{
[DataMember]
private IDictionary<string,object> dynamicProperties = new Dictionary<string,object>();

#region IDynamicMetaObjectProvider implementation
public DynamicMetaObject GetMetaObject (Expression expression)
{
    return new SerializableDynamicMetaObject(expression, 
        BindingRestrictions.GetInstanceRestriction(expression, this), this);
}
#endregion

#region Helper methods for dynamic meta object support
internal object setValue(string name, object value) 
{
    dynamicProperties.Add(name, value);
    return value;
}

internal object getValue(string name) 
{
    object value;
    if(!dynamicProperties.TryGetValue(name, out value)) {
        value = null;
    }
    return value;
}

internal IEnumerable<string> getDynamicMemberNames() 
{
    return dynamicProperties.Keys;
}
#endregion
}


public class SerializableDynamicMetaObject : DynamicMetaObject
{
Type objType;

public SerializableDynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value) 
    : base(expression, restrictions, value) 
{
    objType = value.GetType();
}

public override DynamicMetaObject BindGetMember (GetMemberBinder binder)
{
    var self = this.Expression;
    var dynObj = (SerializableDynamicObject)this.Value;
    var keyExpr = Expression.Constant(binder.Name);
    var getMethod = objType.GetMethod("getValue", BindingFlags.NonPublic | BindingFlags.Instance);
    var target = Expression.Call(Expression.Convert(self, objType),
                                 getMethod,
                                 keyExpr);
    return new DynamicMetaObject(target,
        BindingRestrictions.GetTypeRestriction(self, objType));
}

public override DynamicMetaObject BindSetMember (SetMemberBinder binder, DynamicMetaObject value)
{
    var self = this.Expression;
    var keyExpr = Expression.Constant(binder.Name); 
    var valueExpr = Expression.Convert(value.Expression, typeof(object));
    var setMethod = objType.GetMethod("setValue", BindingFlags.NonPublic | BindingFlags.Instance);
    var target = Expression.Call(Expression.Convert(self, objType),
    setMethod, 
    keyExpr, 
    valueExpr);
    return new DynamicMetaObject(target,
        BindingRestrictions.GetTypeRestriction(self, objType));
}

public override IEnumerable<string> GetDynamicMemberNames ()
{
    var dynObj = (SerializableDynamicObject)this.Value;
    return dynObj.getDynamicMemberNames();
}
}

有一个警告,动态成员可以是任何东西,这意味着在运行时,某人可能会将一个方法分配给这些字段之一。如果在您的应用程序中可能发生这种情况,则需要确保不序列化分配给动态类型的任何方法。我将其留给读者作为练习。

来自这里


1

是否可以允许一个"Interfaced"参数。从而,您可以根据接口值设置来处理多个事情。只是举一个简单的例子。

public enum eWhatAmI
{
   ListedObjects,
   StringArrays,
   Other   
}

public interface IWhatParmType
{
   eWhatAmI whatAmI { get; set; }
}

public class MyListVersion : IWhatParmType
{
   public eWhatAmI whatAmI { get; set; }
   public List<string> whatever { get; set; }

   public MyListVersion()
   {
      whatAmI = eWhatAmI.ListedObjects;
      whatever = new List<string>();
      ... build out list of strings
   }
}

public class MyArrayVersion : IWhatParmType
{
   public eWhatAmI whatAmI { get; set; }
   public string[] whatever { get; set; }

   public MyArrayVersion()
   {
      whatAmI = eWhatAmI.StringArrays;
      ... build out array of strings
   }
}

然后在处理传入参数的过程中,您可以采用任一方式进行处理。
public UnifiedDTO GetAllCardTitle(IWhatParmType parameter, string procedureName)
{
   switch( parameter )
   {
      case (eWhatAmI.ListedObjects):
         // Just for grins, test to make sure object really IS expected list version object
         if( parameter is MyListVersion)
            DoViaList( (MyListVersion)parameter );
         break;

      case (eWhatAmI.StringArrays ):
         if( parameter is MyArrayVersion )
            DoViaArray( (MyArrayVersion)parameter );
         break;
   }
}

private void DoViaList( MyListVersion parm1 )
{
   .. do whatever based on the "List<string>" property
}

private void DoViaArray( MyArrayVersion parm1 )
{
   .. do whatever based on the "string []" property
}

如果您需要为特定对象实例扩展设置,可以在特定的子处理程序方法中处理并填充或强制使用任何默认值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接