2009-10-23 6 views
32

내 프로젝트에는 구조가 다른 다양한 비즈니스 개체의 병합을 관리하는 클래스에서 구현되는 다음과 같은 세 가지 인터페이스가 있습니다.다양한 수의 일반 매개 변수를 사용할 수 있습니까?

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

이 잘 작동하지만 오히려 (예를 아래 params 사용하며, 나는이 유효한 C 번호 아니라는 것을 알고) TSource 수의 매개 변수를 지정 하나 IMerger 인터페이스, 이런 식으로 뭔가를 할 것이다 :

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

이것을 달성 할 수있는 방법이 있습니까? 아니면 기능적으로 동일한 것입니까?

+0

다른 어셈블리에서, 그러나 당신은을 제공 할 수 있습니다 : 당신이 테스트를하려고하면 ('Func' 델리게이트와 마찬가지로) –

+1

이것은 잘못된 의사 코드 일 뿐이지 만,'public interface IMerger { TDestination Merge (TDestination 대상, 매개 변수 TSource 소스); }'. 'params'가 마지막에 올 것입니다. 그러나 크리스챤 헤이 터 (Christian Hayter)에 따르면 기본 클래스를 갖는 것이 유일한 해결 방법입니다. – nawfal

답변

26

수 없습니다. 이는 API의 핵심 부분입니다. 그러나 Type[] 인수를 수락하는 등 측면에서 할 수 있습니다. 당신은 또한 이국적인 "유창한 API/확장 메서드"방식으로 생각할 수도 있지만 솔직히 말해서 가치가 없을 것입니다. 하지만 뭔가 같은 :

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

또는 일반 타입 추론과 :

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

각 단계 만 Execute로 간단한 상점 멀리 할 수있는 작업에 액세스 할 병합합니다.

+0

또한 이러한 접근 방식은 합병에 대한 합리적인 "순서 지정"을 나타낼 수 있습니다. 이는 우리 시나리오에서는 사실이 아닙니다. –

+8

그렇다면 "TSource1 source1, TSource2 source2, TSource3 source3'"질문에서 ... –

+2

내 생각에 source1 .. sourcen은 "이들이 출처"를 나타내는 반면 .Merge 호출 체인은 해당 특정 순서로 병합이 일어나고 있습니다. –

4

params 객체를 파라미터는 끝이나 인수 목록에서 수와 배열에 대한 문법 설탕입니다 수 있습니다

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

당신은 어떤 유형을 사용할 수 있도록하려면

, 단지 대신 TSource의 object[]를 사용합니다.

참고 : MS는 Expression 항목을 처리 할 때도이 "문제"가있었습니다. 많은 수의 대표 인수를 가진 Action<>Func<> 대리인을 생각해 냈지만 각 대리인은 사실 다른 유형입니다.

+0

params를 사용하는 예제는이 컨텍스트에서 params를 사용할 수 없기 때문에 실제로 유효한 C#이 아닙니다.이를 명확하게하기 위해 내 게시물을 업데이트했습니다. –

0

params 키워드는 메소드 서명에만 사용되며, 유형을 장식 할 수있는 것이 아닙니다. 그래서, 유형은 여전히 ​​TSources, 당신은 방법 서명에 params 마지막으로 장식 된 매개 변수 배치 할 수 있습니다

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

어떻게 대답합니까? 'TSource1','TSource2' 등은'TSources'와 어떻게 같습니까? 나는 당신이 그가 게시 한 OP의 최종 예 (비 작동 의사 코드)에서 단서를 얻은 것으로 생각합니다. – nawfal

4

그것은 당신이 당신의 객체가 다른 유형의 객체를 병합 할 수 있도록하려는 여부에 따라 달라집니다 또는 아니.

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

내가 돈 '

이기종 병합
public interface IMerger<TSource, TDestination> { 
    TDestination Merge(IEnumerable<TSource> sources, TDestination destination); 
} 

는 공통 기본 형식에서 파생 된 모든 소스 유형을 필요로 고려 : 균일 병합

는 당신이 필요로하는 모든이입니다 param 배열에 대한 필요성을 확인하고 객체 컬렉션을 전달하십시오.

0

오늘은, 내가이 대리자로 캡슐화 변수 일반적인 입력 매개 변수를 만들 수있는 방법을 사용 MEF를 자동화 해주는 거래에서 근무 : 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 

    } 
} 

나는 일반적으로 & 해결 MEF 개체를 가져 오려면이 도구를 사용하여 extensor (재미있는), 도발 : 선택적으로 가져 오기 생성자 매개 변수를 추가 할 수 있습니다.이 문제는 ComposeExportedValue 함수에서 generic 매개 변수를 사용하므로이 함수를 함수의 변수 params에 추가 할 수 없습니다. 기술, 그래! 예를 들어 ...

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

--- 당신은 가변 인자를 하나의 인터페이스를 만들 수 없습니다

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

    [ImportingConstructor] 
    public Repository(string param) 
    { 
     //add breakpoint 
     this.Param = param; 
    } 
} 
관련 문제