2009-10-23 33 views
32

Trong dự án của tôi, tôi có ba giao diện sau, được triển khai bởi các lớp quản lý việc hợp nhất một loạt các đối tượng nghiệp vụ có cấu trúc khác nhau.Tôi có thể có một số biến số tham số chung không?

public interface IMerger<TSource, TDestination> 
{ 
    TDestination Merge(TSource source, TDestination destination); 
} 

public interface ITwoWayMerger<TSource1, TSource2, TDestination> 
{ 
    TDestination Merge(TSource1 source1, TSource2 source2, TDestination destination); 
} 

public interface IThreeWayMerger<TSource1, TSource2, TSource3, TDestination> 
{ 
    TDestination Merge(TSource1 source1, TSource2 source2, TSource3 source3, TDestination destination); 
} 

này hoạt động tốt, nhưng tôi thà có một IMerger giao diện mà quy định cụ thể một số biến của TSource thông số, một cái gì đó như thế này (ví dụ dưới đây sử dụng params, tôi biết đây không phải là hợp lệ C#):

public interface IMerger<params TSources, TDestination> 
{ 
    TDestination Merge(params TSource sources, TDestination destination); 
} 

Có cách nào để đạt được điều này, hoặc một cái gì đó có chức năng tương đương?

+0

Bạn không thể tạo một giao diện với một số biến của tham số, nhưng bạn có thể cung cấp cho các cùng tên cho tất cả các biến thể của bạn (giống như đại biểu 'Func') –

+1

Trong khi đó chỉ là một mã giả không hợp lệ, nó có ý nghĩa hơn khi viết giống như' giao diện công cộng IMerger { TDestination Merge '(TDestination) đích, params nguồn TSource); } '. 'params' sẽ đến cuối cùng. Nhưng như Christian Hayter nói, có một lớp cơ sở là giải pháp duy nhất – nawfal

Trả lời

26

Bạn không thể. Đó là một phần quan trọng của API. Tuy nhiên, bạn có thể làm điều gì đó xung quanh, chẳng hạn như chấp nhận đối số Type[]. Bạn cũng có thể nghĩ ra một số phương pháp "lưu loát API/mở rộng" kỳ lạ để thực hiện nó, nhưng thành thực mà nói nó có lẽ sẽ không đáng giá; nhưng cái gì đó như:

obj.Merge<FirstType>(firstData).Merge<SecondType>(secondData) 
    .Merge<ThirdType>(thirdData).Execute<TDestination>(dest); 

hoặc với chung suy luận kiểu:

obj.Merge(firstData).Merge(secondData).Merge(thirdData).Execute(dest); 

Mỗi merge bước sẽ đơn giản cửa hàng đi những việc phải làm, chỉ được truy cập bởi Execute.

+0

Ngoài ra, cách tiếp cận như vậy có thể chỉ ra một "thứ tự" hợp lý cho việc hợp nhất, điều này không đúng trong kịch bản của chúng ta. –

+8

Nhưng sau đó, "TSource1 source1, TSource2 source2, TSource3 source3'" từ câu hỏi ... –

+2

Suy nghĩ của tôi là source1 .. sourcen cho biết "đây là các nguồn", trong khi chuỗi các cuộc gọi .Merge cho biết rằng sự hợp nhất đang diễn ra theo thứ tự cụ thể đó. –

4

Các params chỉ có thể có mặt tại danh sách kết thúc hoặc tranh cãi và là cú pháp đường cho một mảng:

public interface IMerger<TSources, TDestination> 
{ 
    TDestination Merge(TDestination destination, params TSource[] sources); 
} 

Nếu bạn muốn cho phép bất kỳ loại được sử dụng, chỉ cần sử dụng object[] thay vì TSource.

Lưu ý: MS có vấn đề này "" khi họ thực hiện công cụ Biểu thức. Họ đã đưa ra một loạt các đại biểu Action<>Func<> với số lượng đối số chung khác nhau, nhưng mỗi đại biểu là một loại khác trên thực tế.

+0

Ví dụ của tôi sử dụng các tham số không thực sự hợp lệ C# vì bạn không thể sử dụng các tham số trong ngữ cảnh này, đã cập nhật bài đăng của mình để làm rõ hơn –

0

Từ khóa params chỉ được sử dụng trong chữ ký phương thức, không phải thứ gì đó mà bạn có thể trang trí loại. Vì vậy, loại vẫn chỉ là TSources, và bạn phải đặt các tham số được trang trí với params cuối cùng trong phương pháp chữ ký:

public interface IMerger<TSources, TDestination> { 
    TDestination Merge(TDestination destination, params TSources[] sources); 
} 
+1

Làm cách nào để trả lời câu hỏi này? 'TSource1',' TSource2' vv tương đương với 'TSources' như thế nào? Tôi nghĩ rằng bạn đã lấy một gợi ý từ ví dụ cuối cùng của OP ông đăng (mã giả không hoạt động). – nawfal

4

Nó phụ thuộc vào việc bạn muốn đối tượng của bạn để có thể kết hợp đối tượng có kiểu khác nhau hoặc không phải.

Đối với một hợp đồng nhất, tất cả các bạn cần là:

public interface IMerger<TSource, TDestination> { 
    TDestination Merge(IEnumerable<TSource> sources, TDestination destination); 
} 

Đối với một hợp đồng nhất, xem xét yêu cầu tất cả các loại nguồn để lấy được từ một loại cơ sở chung:

public interface IMerger<TSourceBase, TDestination> { 
    TDestination Merge(IEnumerable<TSourceBase> sources, TDestination destination); 
} 

I don' t thấy bất kỳ nhu cầu cho một mảng param, chỉ cần vượt qua trong bộ sưu tập của các đối tượng.

0

Hôm nay, tôi làm việc trong một thỏa thuận để automatize MEF, điều này sử dụng một cách để làm cho một thông số biến chung đầu vào, gói gọn trong các đại biểu: S

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using System.ComponentModel.Composition.Primitives; 

namespace MEFHelper 
{ 
    public static class MEFImporter 
    { 
     #region Catalog Field 

     private readonly static AggregateCatalog _catalog; 

     public static AggregateCatalog Catalog { get { return _catalog; } } 

     #endregion 

     static MEFImporter() 
     { 
      //An aggregate catalog that combines multiple catalogs 
      _catalog = new AggregateCatalog(); 
      //Adds all the parts found in all assemblies in 
      //the same directory as the executing program 
      _catalog.Catalogs.Add(
       new DirectoryCatalog(
        System.IO.Path.GetDirectoryName(new Uri(
        System.Reflection.Assembly.GetExecutingAssembly() 
        .CodeBase).AbsolutePath) 
      )); 
     } 

     /// <summary> 
     /// Fill the imports of this object 
     /// </summary> 
     /// <param name="obj">Object to fill the Imports</param> 
     /// <param name="contructorParameters">MEF contructor parameters</param> 
     /// <remarks>Use for MEF importing</remarks> 
     public static void DoImport(this object obj, params MEFParam[] contructorParameters) 
     { 
      //Create the CompositionContainer with the parts in the catalog 
      CompositionContainer container = new CompositionContainer(Catalog, true); 

      //Add the contructor parameters 
      if (contructorParameters != null && contructorParameters.Length > 0) 
      { 
       foreach (MEFParam mefParam in contructorParameters) 
        if (mefParam != null && mefParam.Parameter != null) mefParam.Parameter(container); 
      } 

      //Fill the imports of this object 
      container.ComposeParts(obj); 
     } 

     #region MEFParam 

     /// <summary> 
     /// Creates a Mef Param to do the Import 
     /// </summary> 
     /// <typeparam name="T">Type of the value to store</typeparam> 
     /// <param name="value">Value to store</param> 
     /// <param name="key">Optional MEF label</param> 
     /// <returns>A MEF paramameter</returns> 
     /// <remarks>This retuns a MEF encapsulated parameter in a delegate</remarks> 
     public static MEFParam Parameter<T>(T value, string key = null) 
     { 
      Action<CompositionContainer> param; 
      if (string.IsNullOrWhiteSpace(key)) 
       param = p => p.ComposeExportedValue(value); 
      else param = p => p.ComposeExportedValue(key, value); 
      return new MEFParam(param); 
     } 

     /// <summary> 
     /// Mef Param to do the Import 
     /// </summary> 
     public class MEFParam 
     { 
      protected internal MEFParam(Action<CompositionContainer> param) 
      { 
       this.Parameter = param; 
      } 
      public Action<CompositionContainer> Parameter { get; private set; } 
     } 

     #endregion 

    } 
} 

tôi sử dụng công cụ này để nhập & đối tượng quyết tâm MEF quát với một extensor (thú vị), taunt: bạn có thể thêm tùy chọn các tham số constructor nhập khẩu, vấn đề này là trong hàm ComposeExportedValue thats sử dụng một tham số chung, bạn không thể thêm điều này vào một biến params trong một hàm, với điều này kỹ thuật, vâng! nếu bạn cố gắng để kiểm tra: ví dụ ...

public class Factory : IDisposable 
{ 

    [Import(typeof(IRepository))] 
    private Repository _repository = null; 

    public Factory() 
    { 
     MEFImporter.DoImport(this, MEFImporter.Parameter("hello")); 
    } 

    public IRepository Repository 
    { 
     get 
     { 
      return _repository; 
     } 
    } 

    public void Dispose() 
    { 
     _repository = null; 
    } 
} 

--- Trong lắp ráp khác

[Export(typeof(IRepository))] 
public class Repository : IRepository 
{ 
    string Param; 

    [ImportingConstructor] 
    public Repository(string param) 
    { 
     //add breakpoint 
     this.Param = param; 
    } 
} 
Các vấn đề liên quan