C #에는 확장 속성이 있습니까?
예를 들어, DateTimeFormatInfo
호출 ShortDateLongTimeFormat
할 확장 속성을 추가 할 수 ShortDatePattern + " " + LongTimePattern
있습니까?
답변
현재 Roslyn 컴파일러는 여전히 기본적으로 지원하지 않습니다 …
지금까지 확장 속성은 이전 버전의 C # 표준에 포함될만큼 가치있는 것으로 보이지 않았습니다. C # 7 과 C # 8.0 은 이것을 제안 챔피언으로 보았지만 아직 구현되지 않았지만, 이미 구현이 있더라도 처음부터 올바르게 만들고 싶어하기 때문에 아직 출시되지 않았습니다.
그러나 그것은 …
가 확장 회원 에서 항목 C # 7 작업 목록 이 가까운 미래에 지원 될 수 있도록. 확장 속성의 현재 상태는 Github의 관련 항목에서 찾을 수 있습니다 .
그러나 특히 속성과 정적 클래스 또는 필드에 중점을 둔 “모든 것을 확장” 하는 더 유망한 주제가 있습니다.
또한 해결 방법을 사용할 수 있습니다
이 기사 에서 지정한대로 , TypeDescriptor
런타임시이 기능을 사용하여 객체 인스턴스에 속성을 첨부 할 수 있습니다 . 그러나 표준 속성의 구문을 사용하지 않습니다. 데이터가 클래스에 저장 될 때 확장 메소드의 별명
과 같은 확장 특성을 정의 할 수있는 가능성을 추가하는 구문 설탕과는 조금 다릅니다 .string Data(this MyClass instance)
string GetData(this MyClass instance)
C # 7이 모든 기능 확장 (속성 및 필드)을 제공하기를 희망하지만 그 시점에서는 시간 만 알 수 있습니다.
또한 내일의 소프트웨어가 커뮤니티에서 제공 될 것이므로 자유롭게 기여하십시오.
업데이트 : 2016 년 8 월
닷넷 팀 은 C # 7.0의 새로운 기능 과 Mads Torgensen 의 의견을 게시했습니다 .
확장 속성 : 우리는 다른 종류의 확장 멤버와 함께 여름에 실험을 통해 (화려한!) 인턴을 구현했습니다. 우리는 이것에 관심을 가지고 있지만 큰 변화이며 그만한 가치가 있다고 확신해야합니다.
확장 속성과 다른 멤버는 여전히 Roslyn의 향후 릴리스에 포함될 좋은 후보이지만 7.0은 아닙니다.
업데이트 : 2017 년 5 월
확장 멤버 는 확장 된 모든 문제 와 중복되어닫혔습니다. 주요 논의는 실제로 유형 확장성에 대한 광범위한 의미에서 논의되었습니다. 이 기능은 이제 제안서로 추적되었으며 7.0 마일스톤 에서 제거되었습니다.
업데이트 : 2017 년 8 월-C # 8.0 제안 기능
여전히 제안 된 기능으로 남아 있지만 구문의 내용을보다 명확하게 확인할 수 있습니다. 이것이 확장 메소드의 새로운 구문이 될 것임을 명심하십시오.
public interface IEmployee
{
public decimal Salary { get; set; }
}
public class Employee
{
public decimal Salary { get; set; }
}
public extension MyPersonExtension extends Person : IEmployee
{
private static readonly ConditionalWeakTable<Person, Employee> _employees =
new ConditionalWeakTable<Person, Employee>();
public decimal Salary
{
get
{
// `this` is the instance of Person
return _employees.GetOrCreate(this).Salary;
}
set
{
Employee employee = null;
if (!_employees.TryGetValue(this, out employee)
{
employee = _employees.GetOrCreate(this);
}
employee.Salary = value;
}
}
}
IEmployee person = new Person();
var salary = person.Salary;
부분 클래스와 비슷하지만 다른 어셈블리에서 별도의 클래스 / 유형으로 컴파일됩니다. 이런 식으로 정적 멤버와 연산자를 추가 할 수도 있습니다. 에서 언급 한 바와 같이 MADS Torgensen 포드 캐스트 , (이 클래스에 개인 인스턴스 멤버를 추가 할 수 있도록) 확장은 인스턴스에 연결된 개인 인스턴스 데이터를 추가 할 수 없습니다 의미 어떤 상태가되지 않습니다 . 그 이유는 내부 사전을 관리한다는 것을 의미하고 메모리 관리 등이 어려울 수 있기 때문입니다. 이를 위해 앞에서 설명한 TypeDescriptor
/ ConditionalWeakTable
기술을 계속 사용할 수 있으며 속성 확장명을 사용하면 멋진 속성 아래에 숨길 수 있습니다.
이 문제 를 암시하는 것처럼 구문은 여전히 변경 될 수 있습니다 . 예를 들어, 일부는 더 자연스럽고 덜 자바와 관련이 있다고 느낄 extends
수 있습니다 for
.
2018 년 12 월 업데이트-역할, 확장 및 정적 인터페이스 멤버
확장은 모든 GitHub 티켓 의 끝으로 설명 된 몇 가지 단점 때문에 C # 8.0으로 만들지 못했습니다 . 따라서 디자인을 개선하기위한 탐구가있었습니다. 여기서 , MADS Torgensen는 무엇인지 설명 역할과 확장 그리고 그들은 어떻게 다른지 :
역할을 통해 특정 유형의 특정 값에 인터페이스를 구현할 수 있습니다. 확장 기능을 사용하면 특정 코드 영역 내에서 지정된 유형의 모든 값에 인터페이스를 구현할 수 있습니다.
두 가지 사용 사례에서 이전 제안의 일부에서 볼 수 있습니다. 확장을위한 새로운 구문은 다음과 같이 될 것이다 :
public extension ULongEnumerable of ulong
{
public IEnumerator<byte> GetEnumerator()
{
for (int i = sizeof(ulong); i > 0; i--)
{
yield return unchecked((byte)(this >> (i-1)*8));
}
}
}
그러면 당신은 이것을 할 수 있습니다 :
foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
WriteLine($"{e.Current:X}");
}
그리고에 대한 정적 인터페이스 :
public interface IMonoid<T> where T : IMonoid<T>
{
static T operator +(T t1, T t2);
static T Zero { get; }
}
추가 확장 속성 에 int
와 치료 int
로 IMonoid<int>
:
public extension IntMonoid of int : IMonoid<int>
{
public static int Zero => 0;
}
답변
C # 3.0에는 존재하지 않으며 4.0에는 추가되지 않습니다. C #에 필요한 기능 목록에 있으므로 향후 추가 될 수 있습니다.
이 시점에서 가장 좋은 방법은 GetXXX 스타일 확장 방법입니다.
답변
아니요, 존재하지 않습니다.
나는 C # 팀이 확장 생성자와 연산자와 함께 한 시점에서 (또는 적어도 Eric Lippert가) 고려하고 있음을 알고 있습니다. 그들이 C # 4의 일부가 될 것이라는 어떠한 증거도 보지 못했습니다.
편집 : 그들은 C # 5에 나타나지 않았으며 2014 년 7 월 현재 C # 6에도없는 것처럼 보이지 않습니다.
2012 년 11 월부터 Microsoft C # 컴파일러 팀의 수석 개발자 인 Eric Lippert 는 2009 년 10 월에 이에 대해 블로그를 작성했습니다.
답변
업데이트 ( 이 업데이트를 지적한 @chaost 덕분에 ) :
Mads Torgersen : “확장 된 모든 것이 C # 8.0으로 만들어지지는 않았습니다. 언어의 미래에 대한 매우 흥미로운 토론에서”잡혔습니다 “. 이제 우리는 미래의 가능성을 방해하는 방식으로 언어를 추가하십시오. 때로는 언어 디자인이 매우 긴 게임입니다! “
출처 : https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/의 의견 섹션
나는 몇 년 동안이 질문을 열어 이것을 구현하기를 희망하면서 몇 번이나 세지 않았습니다.
글쎄, 마침내 우리는 모두 기뻐할 수 있습니다! Microsoft는 곧 C # 8 릴리스에서이 기능을 소개 할 것입니다.
그래서 이것을하는 대신에 …
public static class IntExtensions
{
public static bool Even(this int value)
{
return value % 2 == 0;
}
}
우리는 마침내 그렇게 할 수 있습니다 …
public extension IntExtension extends int
{
public bool Even => this % 2 == 0;
}
출처 : https://blog.ndepend.com/c-8-0-features-glimpse-future/
답변
@Psyonity가 언급했듯이 conditionalWeakTable을 사용하여 기존 객체에 속성을 추가 할 수 있습니다. 동적 ExpandoObject와 결합하여 몇 줄로 동적 확장 속성을 구현할 수 있습니다.
using System.Dynamic;
using System.Runtime.CompilerServices;
namespace ExtensionProperties
{
/// <summary>
/// Dynamically associates properies to a random object instance
/// </summary>
/// <example>
/// var jan = new Person("Jan");
///
/// jan.Age = 24; // regular property of the person object;
/// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
///
/// if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
/// Console.WriteLine("Jan drinks too much");
/// </example>
/// <remarks>
/// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
/// </remarks>
public static class ObjectExtensions
{
///<summary>Stores extended data for objects</summary>
private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();
/// <summary>
/// Gets a dynamic collection of properties associated with an object instance,
/// with a lifetime scoped to the lifetime of the object
/// </summary>
/// <param name="obj">The object the properties are associated with</param>
/// <returns>A dynamic collection of properties associated with an object instance.</returns>
public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject());
}
}
사용 예는 xml 주석에 있습니다.
var jan = new Person("Jan");
jan.Age = 24; // regular property of the person object;
jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
{
Console.WriteLine("Jan drinks too much");
}
jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection
답변
최근에 이것이 필요했기 때문에 답의 출처를 살펴 보았습니다.
보다 역동적 인 버전을 만들었습니다.
public static class ObjectExtenders
{
static readonly ConditionalWeakTable<object, List<stringObject>> Flags = new ConditionalWeakTable<object, List<stringObject>>();
public static string GetFlags(this object objectItem, string key)
{
return Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value;
}
public static void SetFlags(this object objectItem, string key, string value)
{
if (Flags.GetOrCreateValue(objectItem).Any(x => x.Key == key))
{
Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value = value;
}
else
{
Flags.GetOrCreateValue(objectItem).Add(new stringObject()
{
Key = key,
Value = value
});
}
}
class stringObject
{
public string Key;
public string Value;
}
}
아마 많이 향상 될 수 있습니다 (이름 대신, 문자열 대신 동적), 나는 현재 해킹 된 ConditionalWeakTable과 함께 CF 3.5에서 이것을 사용합니다 ( https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4 )